consider the code below:
-module(except).
-compile(export_all).
divone(X)-> erlang:error({badnews,erlang:get_stacktrace()}),1/X-1.
tryreturn(X)->
try divone(X) of
Val->{result,2/Val}
catch
exit:Reason->{exit,Reason};
throw:Throw->{throw,Throw};
error:Error->{error,Error}
end.
test the code in shell:
Eshell V5.9.1 (abort with ^G)
1> c(except).
{ok,except}
2> except:tryreturn(10). **%why cant't get stack trace info here?**
{error,{badnews,[]}}
3> except:tryreturn(10). **%why can get here?**
{error,{badnews,[{except,divone,1,
[{file,"except.erl"},{line,4}]},
{except,tryreturn,1,[{file,"except.erl"},{line,7}]},
{erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,576}]},
{shell,exprs,7,[{file,"shell.erl"},{line,668}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}}
If there hasn't been any exceptions, the stacktrace returned by erlang:backtrace() is empty.
Something more helpful than erlang:backtrace() for you would be something that includes the instruction pointer and the process's callstack, irrespective of if you've caught an exception.
This should be the ticket:
io:format("~s~n", [element(2, process_info(self(), backtrace))]).
(Naturally, self can be freely exchanged with another Pid)
According to documentation:
Gets the call stack back-trace (stacktrace) of the last exception in the calling process as a list of {Module,Function,Arity,Location} tuples. Field Arity in the first tuple can be the argument list of that function call instead of an arity integer, depending on the exception.
Note the last exception in above text. During your first call, there was not any exception yet, so there is not any stacktrace to return. Then you make error class[1] exception using erlang:error/1 so next call returns stacktrace of the previous call!
There is idiom how to get stacktrace of the current code:
try throw(foo) catch foo -> erlang:get_stacktrace() end.
or using older (obsolete) way:
catch throw(foo), erlang:get_stacktrace().
[1]: There are three classes of exception: throw, error, exit.
Related
I having crypto_server problems:
=CRASH REPORT==== 23-Jul-2019::10:20:17 ===
crasher:
pid: <0.49.0>
registered_name: crypto_server
exception exit: {einval,
[{erlang,open_port,
[{spawn,
"crypto_drv elibcrypto
c:/myapp/lib/crypto-1.5.3/priv/lib/win32/elibcrypto"},
[]]},
{crypto_server,open_ports,2},
{gen_server,init_it,6},
{proc_lib,init_p_do_apply,3}]}
in function gen_server:init_it/6
initial call: crypto_server:init/1
ancestors: [crypto_sup,<0.47.0>]
messages: []
links: [<0.48.0>]
dictionary: []
trap_exit: true
status: running
heap_size: 610
stack_size: 23
reductions: 425
neighbours:
and the application doesn't start:
Kernel pid terminated (application_controller)
({application_start_failure,crypto,{shutdown,{crypto_app,start,[normal,[]]}}})
einval is a is a linux error that means invalid argument. Erlang returns quite a few of those types of errors back to the user. If you need a handy lookup table, you check look here.
I'm guessing the version of OpenSSL you have installed is incompatible with the old version of erlang. You could always start a trace on the init and see what's happening in during all of the message passing. You'll have to add the trace to your start up code before starting up the crypto lib. Here's a basic primer on tracing.
You must start the tracer program:
dbg:tracer().
Then you need to identify which process(es) you'd like to trace. The simple version is to watch all processes. (c is short for [call], which means trace all function calls.)
dbg:p(all, c).
Finally, say what function calls you're interested in tracing by Module; Module and Function; or Module, Function, and Arity. You can use '_' in place of any of them.
dbg:tpl(Module, cx).
dbg:tpl(Module, Function, cx).
dbg:tpl(Module, Function, Arity, cx).
You can turn tracing off with a similar function that disables tracing for all functions; by Module; by Module and Function; or by Module, Function, and Arity. Again, you can use '_' in place of any of them.
dbg:ctpl().
dbg:ctpl(Module).
dbg:ctpl(Module, Function).
dbg:ctpl(Module, Function, Arity).
A simple, working example that you can copy/paste into a fresh repl:
dbg:tracer().
dbg:p(all, c).
dbg:tpl(file, open, cx).
file:open("idontexist", []).
dbg:ctpl(file).
file:open("idontexist", []).
That should produce something like:
1> dbg:tracer().
{ok,<0.299.0>}
2> dbg:p(all, c).
{ok,[{matched,engine#ryan,215}]}
3> dbg:tpl(file, open, cx).
{ok,[{matched,node#sam,1},{saved,cx}]}
4> file:open("idontexist", []).
(<0.50.0>) call file:open("idontexist",[]) ({erl_eval,do_apply,6})
(<0.50.0>) returned from file:open/2 -> {error,enoent}
{error,enoent}
5> dbg:ctpl(file).
{ok,[{matched,node#sam,95}]}
6> file:open("idontexist", []).
{error,enoent}
7>
I've guessed a couple of the erlang:system_info/1 variants such as:
10> erlang:system_info(schedulers).
4
11> erlang:system_info(cpu).
** exception error: bad argument
in function erlang:system_info/1
called as erlang:system_info(cpu)
12> erlang:system_info(cpu_arch).
** exception error: bad argument
in function erlang:system_info/1
called as erlang:system_info(cpu_arch)
13> erlang:system_info(memory).
** exception error: bad argument
in function erlang:system_info/1
called as erlang:system_info(memory)
14> erlang:system_info(version).
"5.10.4"
But is there a way, either via introspection, or a global database of some sort, to list all the available system_info arguments ?
Refer to the documentation for erlang:system_info/1. It's listed over several sections with descriptions for what each atom represents. This is the most comprehensive list of supported atoms outside of the Erlang/OTP source itself (and there are a few undocumented parameters).
There is no language feature which would allow you to list all of the possible atoms.
I'm a meck (and Erlang) newbie and I'm struggling a bit with meck. I'm getting the following error:
=ERROR REPORT==== 27-Jan-2014::16:20:05 ===
Error in process <0.1825.0> with exit value: {{not_mocked,substatsDb},
[{meck_proc,gen_server,3,[{file,"src/meck_proc.erl"},{line,443}]},{meck_code_gen,exec,4,
[{file,"src/meck_code_gen.erl"},{line,147}]},{substats,loop,1,
[{file,"/Users/uyounri/gitsandbox/subpub/src/su...
At the beginning of my test I declare the module to be mocked:
meck:new(substats)
At the very end of my test the last thing I do is to unload the module that was mocked mocked:
meck:unload(substats)
The mocking seems to be working as expected until towards the end of the test when the above error is produced.
Thanks,
Rich
EDIT
Adding 2 ?debugFmt() lines seems to have fixed the problem; at least I no longer get the error. Here's the complete function that was modified:
stop(_) ->
meck:expect(substatsDb, stop, 1, fun(dbconn) -> ok end),
substats:stop(),
%% Note: this and the next ?debugFmt() calls prevent a meck
%% exit error. They both have to be present to prevent the error
?debugFmt("stop:~n", []),
meck:unload(substatsDb),
?debugFmt("stop: exit~n", []).
Have you tried adding the option passthrough when mocking the module?
meck:new(substatsDb, [passthrough])
Also, you are using the module "substatsDb" in the meck:expect call, but doing the meck:new for another module (substats), you should be doing everything for the same modules (new, expect, and unload)
hope it helps!
when i read an artical from learnyousomeerlang.com,I got a question.
http://learnyousomeerlang.com/errors-and-processes
It says that:
Exception source: exit(self(), kill)
Untrapped Result: ** exception exit: killed
Trapped Result: ** exception exit: killed
Oops, look at that. It seems like this one is actually impossible to trap. Let's check something.
but it does not comply with what I test with the code blow:
-module(trapexit).
-compile(export_all).
self_kill_exit()->
process_flag(trap_exit,true),
Pid=spawn_link(fun()->timer:sleep(3000),exit(self(),kill) end),
receive
{_A,Pid,_B}->io:format("subinmain:~p output:~p~n",[Pid,{_A,Pid,_B}])
end.
oupput is:
**4> trapexit:self_kill_exit().
subinmain:<0.36.0> output:{'EXIT',<0.36.0>,killed}**
and does not comply with Trapped Result: ** exception exit: killed said before . which is right???
The call to self in the body of the function passed as an argument to spawn_link doesn't return the process calling spawn_link. It's being evaluated in the newly spawned process and as a result it will return its pid. Make a following change.
-module(trapexit).
-compile(export_all).
self_kill_exit()->
process_flag(trap_exit,true),
Self=self(),
Pid=spawn_link(fun()->timer:sleep(3000),exit(Self,kill) end),
receive
{_A,Pid,_B}->io:format("subinmain:~p output:~p~n",[Pid,{_A,Pid,_B}])
end.
Now it should work as expected.
10> c(trapexit).
{ok,trapexit}
11> trapexit:self_kill_exit().
** exception exit: killed
The book is right. Trapping exit(self(), kill) is not possible.
I am trying to use the Erlang ddb module to interface with amazon's DynamoDB and I am getting a strange error while trying to set things up. I call ddb_iam:credentials() and it returns 'ok', but the ddb_iam:token() function crashes with an error as such: (this example is taken right from the manual page.
ddb_iam:credentials(AccessKey, SecretKey).
{ok, Key, Secret, Token} = ddb_iam:token(129600).
** exception error: bad argument
in function ets:lookup/2
called as ets:lookup(ibrowse_lb,{"sts.amazonaws.com",443})
in call from ibrowse:send_req/6 (src/ibrowse.erl, line 313)
in call from ddb_aws:retry/4 (src/ddb_aws.erl, line 50)
in call from ddb_iam:token/1 (src/ddb_iam.erl, line 63)
8>
It sounds like ibrowse is not started:
ibrowse:start().