2010-02-12 118 views
8

我需要在外部系统中调试某个模块, 模块具有公共函数foo() - 如何知道从哪个地方(模块和函数名称) foo()给定模块被调用?我的意思是一堆电话。erlang调用堆栈

PS:我不能停止的系统,所有的工作,我可以通过重载做到这一点模块(但SOM调试信息)

-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 
+0

我有修改我的例子,请注释 – vinnitu 2010-02-12 16:34:32

+1

请注意,在上面的例子中,对给定:foo()的调用是尾部调用 - 这意味着堆栈上不会留下任何痕迹每个定义)。如果您需要进行这种调试,您应该了解有关Erlang的跟踪。 – RichardC 2010-03-05 15:11:17

回答

17

这里有一个简单的一招:

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

这可能工作:

where_am_i() -> 
    try throw(a) 
    catch throw:a -> 
      erlang:get_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被称为。

1
 
io:format("~s~n", [element(2, process_info(self(), backtrace))]). 

self()可以被任何其他pid替换(rpc:pinfo甚至可以与远程procs一起工作)。如果你甚至不能修改源或光束,这将有所帮助。

0

这是我做这个代码:

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). 

列表是系统中的自定义模块。改用你的foo模块。