【问题标题】:How to show Erlang call stack?如何显示 Erlang 调用堆栈?
【发布时间】:2011-01-16 03:47:08
【问题描述】:

我需要调试外部系统中的一些模块。该模块具有公共功能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

【问题讨论】:

  • 我修改了我的例子,请评论
  • 请注意,在上面的示例中,对 given:foo() 的调用是尾调用 - 这意味着堆栈上不会留下任何痕迹(根据定义)。如果你需要做这种调试,你应该学习 Erlang 中的跟踪。

标签: erlang stack call


【解决方案1】:

这可能有效:

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,因为在调用where_am_i 时,已经离开了foo 的调用框架。

【讨论】:

    【解决方案2】:

    这是我的代码:

    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 模块。

    【讨论】:

      【解决方案3】:
      io:format("~s~n", [element(2, process_info(self(), backtrace))])。

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

      【讨论】:

        【解决方案4】:

        这是一个简单的技巧:

        Trace = try throw(42) catch 42 -> erlang:get_stacktrace() end,
        erlang:display(Trace)
        

        【讨论】:

        • 不错的技巧,但是当我尝试时出现编译错误erlang:get_stacktrace/0: deprecated; use the new try/catch syntax for retrieving the stack backtrace
        • 较新的变种是try throw(42) catch _:_:Stk -> Stk end,
        猜你喜欢
        • 2021-12-06
        • 2014-11-13
        • 1970-01-01
        • 2012-01-04
        • 1970-01-01
        • 1970-01-01
        • 2018-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多