dbg:tracer visualizing recursive functions e.g. by indenting
I have the problem debugging an complicated recursive function I'm using the idiom:
dbg:tracer(),dbg:p(all开发者_运维百科,c),dbg:tpl(Mod,Fun1,x),dbg:tpl(Mod,Fun2,x)...
This gives me a flat list of calls to all functions where it is very hard to find out which return belongs to which call.
Is there a easy way to make this more readable e.g. by indenting.
I could just post process the text produced and indent for each call, and outdent for each return, but this sounds not very elegant to me.
In the meantime I figured it out how to do this, its actually not too hard. To have a process handling the trace message output you just have to use dbg:trace/2,3
and write one function that does the formatting.
We write a small module containing the function to pass to 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.
The function takes two arguments, in the first it gets passed the trace message which is a tuple with convenient fields. To find out how the messages you want to format are structured just start with a simple function that prints everything like the last clause of the example function.
The second format is a kind of state that could contain any data. We pass the initial value when calling dbg:trace
and return the next value from our function.
In the nested
example we just pass the indent level which will be incremented and decremented in the call
and return_from
clauses.
Now lets try this out, first calling dbg:tracer/2
, first parameter must be the atom process
, second parameter a tuple containing our newly written fun and the initial value for the state param.
1> dbg:tracer(process, {fun trtool:nested/2, 0}).
{ok,<0.70.0>}
Then we set up tracing as before:
2> dbg:p(all, c), dbg:tpl(user_default,hop,x),dbg:tpl(user_default,rec,x).
{ok,[{matched,nonode@nohost,2},{saved,x}]}
Then we start our function call to trace and the nesting can be easily followed:
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>
There is not way you can do that with the current dbg tracer process, you would have to write your own. If you start dbg:tracer/2 and use a process or port to capture the data and print it the way you want it to be.
It is probably faster and easier though to (as you say) parse the data post tracing and format it then.
精彩评论