dbg:tracer可视化递归函数,例如通过缩进

时间:2011-02-26 10:49:16

标签: debugging erlang trace

我有调试复杂递归函数的问题我正在使用这个成语:

dbg:tracer(),dbg:p(all,c),dbg:tpl(Mod,Fun1,x),dbg:tpl(Mod,Fun2,x)...

这给了我一个对所有函数的调用的平面列表,其中很难找出哪个函数返回属于哪个函数。

是否有一种简单的方法可以使其更具可读性,例如通过缩进。

我可以只为每次调用发布生成和缩进的文本进行处理,并为每次回复发布,但这听起来不是很优雅。

2 个答案:

答案 0 :(得分:5)

与此同时,我想出了如何做到这一点,实际上并不太难。要让进程处理跟踪消息输出,您只需使用dbg:trace/2,3并编写一个执行格式化的函数。

我们编写一个包含要传递给dbg:trace的函数的小模块:

-module(trtool).
-export([nested/2]).

nested({trace, _Pid, call, {Mod, Fun, Param}}, Level) ->
    io:format("~s~p:~p ~p\n", 
              [lists:duplicate(Level, "|   "), Mod, Fun, Param]),
    Level + 1;
nested({trace, _Pid, return_from, {Mod, Fun, Arity}, Rval}, Level) ->
    L = Level - 1,
    io:format("~s~p:~p/~b -> ~p\n", 
              [lists:duplicate(L, "|   "), Mod, Fun, Arity, Rval]),
    L;
nested(Any, Level) ->
    io:format("trace_msg: ~p\n", [Any]),
    Level.

该函数有两个参数,第一个传递跟踪消息,它是一个带有方便字段的元组。要了解如何构建要格式化的消息,只需从一个简单的函数开始,该函数打印所有内容,如示例函数的最后一个句子。

第二种格式是一种可以包含任何数据的状态。我们在调用dbg:trace时传递初始值,并从函数中返回下一个值。

nested示例中,我们只传递缩进级别,该缩进级别将在callreturn_from子句中递增和递减。

现在让我们尝试一下,首先调用dbg:tracer/2,第一个参数必须是原子process,第二个参数是包含我们新编写的乐趣的元组和状态参数的初始值。

1> dbg:tracer(process, {fun trtool:nested/2, 0}).                         
{ok,<0.70.0>}

然后我们像以前一样设置跟踪:

2> dbg:p(all, c), dbg:tpl(user_default,hop,x),dbg:tpl(user_default,rec,x).
{ok,[{matched,nonode@nohost,2},{saved,x}]}

然后我们开始对trace进行函数调用,并且可以很容易地遵循嵌套:

3> rec(3).                                                                
user_default:rec [3]
|   user_default:rec [3,1,3]
|   |   user_default:rec [3,1,2]
|   |   |   user_default:rec [3,1,1]
|   |   |   |   user_default:rec [3,1,0]
|   |   |   |   |   user_default:hop [3,1,0]
|   |   |   |   |   user_default:hop/3 -> {3,21}
|   |   |   |   user_default:rec/3 -> {3,21,1}
|   |   |   |   user_default:rec [6,2,-1]
|   |   |   |   |   user_default:hop [6,2,1]
|   |   |   |   |   user_default:hop/3 -> {2,46}
|   |   |   |   user_default:rec/3 -> {2,46,1}
|   |   |   user_default:rec/3 -> {5,67,2}
|   |   |   user_default:rec [8,3,0]
|   |   |   |   user_default:hop [8,3,0]
|   |   |   |   user_default:hop/3 -> {3,144}
|   |   |   user_default:rec/3 -> {3,144,1}
|   |   user_default:rec/3 -> {8,211,3}
|   |   user_default:rec [11,4,1]
|   |   |   user_default:rec [11,4,0]
|   |   |   |   user_default:hop [11,4,0]
|   |   |   |   user_default:hop/3 -> {3,258}
|   |   |   user_default:rec/3 -> {3,258,1}
|   |   |   user_default:rec [14,5,-1]
|   |   |   |   user_default:hop [14,5,1]
|   |   |   |   user_default:hop/3 -> {2,260}
|   |   |   user_default:rec/3 -> {2,260,1}
|   |   user_default:rec/3 -> {5,518,2}
|   user_default:rec/3 -> {13,729,5}
user_default:rec/1 -> {15,729}
{15,729}
4>

答案 1 :(得分:2)

使用当前的dbg跟踪器进程无法做到这一点,您必须自己编写。如果启动dbg:tracer / 2并使用进程或端口捕获数据并按照您希望的方式进行打印。

虽然(正如你所说)解析跟踪后的数据然后格式化它可能更快更容易。