9

我需要调试外部系统中的一些模块。该模块具有公共功能foo()- 我如何知道调用 foo() 给定模块的位置(模块和函数名称)?我的意思是一堆电话。

我无法停止系统,我可以通过重新加载这个模块来完成所有工作(但有一些调试信息)。

-module(given).
-export(foo/0).

foo() ->
    %% here is my debug - and
    %% i need here(!) known about unknown_module:unknown_foo!
    ok.

---
-module(unknown_module).
..

unknown_foo() ->
    given:foo().  %% see above
4

4 回答 4

20

这是一个简单的技巧:

Trace = try throw(42) catch 42 -> erlang:get_stacktrace() end,
erlang:display(Trace)
于 2010-02-12T15:31:53.947 回答
3

这可能有效:

where_am_i() ->
    try throw(a)
    catch throw:a:Stacktrace ->
            Stacktrace
    end.

除了它不适用于尾调用。例如,给定这两个函数:

foo() ->
    where_am_i().

bar() ->
    X = where_am_i(),
    {ok, X}.

我得到这些结果:

4> foo:foo().
[{foo,where_am_i,0},
 {erl_eval,do_apply,5},
 {shell,exprs,6},
 {shell,eval_exprs,6},
 {shell,eval_loop,3}]
5> foo:bar().
{ok,[{foo,where_am_i,0},
     {foo,bar,0},
     {erl_eval,do_apply,5},
     {shell,exprs,6},
     {shell,eval_exprs,6},
     {shell,eval_loop,3}]}

也就是说,我只能看到bar,因为foo调用时已经留下了调用框架where_am_i

于 2010-02-12T15:32:27.143 回答
2
io:format("~s~n", [element(2, process_info(self(), backtrace))])。

self() 可以被任何其他 pid 替换(rpc:pinfo 甚至应该与远程 procs 一起使用)。如果您甚至无法修改源或光束,这将很有帮助。

于 2010-02-12T23:01:49.390 回答
1

这是我这样做的代码:

format_stack_entry(S) ->
    {Module,Fun,Arity,[{file,File},{line,Line}]}=S,
    io_lib:format("{~p,~p,~p,[{file,~p},{line,~p]}",[Module,Fun,Arity,File,Line]).
stacktop([Top|_]) ->
    Top.
ancestor(N) ->
    {_,Stacktrace}=erlang:process_info(self(),current_stacktrace),
    ancestor(N+1,Stacktrace).
ancestor(1,S) ->
    format_stack_entry(stacktop(S));
ancestor(N,[_|T]) ->
    ancestor(N-1,T).

info(Format)      -> io:format(lists:concat([ancestor(2),Format,"\r"])).
info(Format,Args) -> io:format(lists:concat([ancestor(2),Format,"\r"]),Args).

Lists 是系统中的自定义模块。请改用您的 foo 模块。

于 2015-12-15T23:17:09.087 回答