Search code examples
debuggingerlangtrace

Eper redbug, print line number in message


Here are some messages from using redbug in the shell:

% 02:49:02 <0.116.0>({cowboy_protocol,init,4})
% func1:start(<<"/second">>, [some])

% 02:49:02 <0.116.0>({cowboy_protocol,init,4})
% func1:looper(<<"/home/second">>, #{data => []}])

Is there are way to also print line numbers in redbug messages?

redbug:help() does show this:

print_fun    ()            custom print handler, fun/1 or fun/2;
                             fun(TrcMsg) -> <ignored>
                             fun(TrcMsg,AccOld) -> AccNew

But there is no good explanation anywhere how to use it, so I couldn't try to see if I could add line numbers to the message


Solution

  • It doesn't seem you can do it in any straight forward way.

    Easiest way to check this, it to just print all data you receive in your print_fun

    1> PrintFun = fun (Msg) -> io:format( ">>> ~p~n" , [Msg]) end.
    #Fun<erl_eval.6.90072148>
    2> redbug:start("erlang" , [{print_fun, PrintFun}]).
    {30,249}
    >>> {call,{{erlang,demonitor,[#Ref<0.0.0.40>]},<<>>},
              {<0.33.0>,{erlang,apply,2}},
              {11,40,31,554200}}
    >>> {call,{{erlang,atom_to_list,['PrintFun']},<<>>},
              {<0.33.0>,{erlang,apply,2}},
              {11,40,31,554210}}
    >>> {call,{{erlang,group_leader,[]},<<>>},
              {<0.33.0>,{erlang,apply,2}},
              {11,40,31,554213}}
    >>> {call,{{erlang,monitor,[process,<0.26.0>]},<<>>},
              {<0.33.0>,{erlang,apply,2}},
              {11,40,31,554215}}
    >>> {call,{{erlang,port_control,[#Port<0.491>,101,[]]},<<>>},
              {<0.24.0>,user_drv},
              {11,40,31,554231}}
    >>> {call,{{erlang,module_loaded,[calendar]},<<>>},
              {<0.20.0>,code_server},
              {11,40,31,554257}}
    >>> {call,{{erlang,atom_to_list,[calendar]},<<>>},
              {<0.20.0>,code_server},
              {11,40,31,554263}}
    >>> {call,{{erlang,'++',["calendar",".beam"]},<<>>},
              {<0.20.0>,code_server},
              {11,40,31,554265}}
    >>> {call,{{erlang,'++',["ebin","/calendar.beam"]},<<>>},
              {<0.20.0>,code_server},
              {11,40,31,554268}}
    >>> {call,{{erlang,whereis,[erl_prim_loader]},<<>>},
              {<0.20.0>,code_server},
              {11,40,31,554270}}
    redbug done, msg_count - 10
    

    As you can see, all you get is MFA ({Module, Function, Arguments}), calling process, and time stamp.

    To get actual line of function call you would have to dig into debug_info attached to beam file (if there is any) with beam_lib module. I think seampleas way to do it would be using beam_lib:chunks( Module, [abstract_code])., just like this

    {ok,{redbug,[{abstract_code,{raw_abstract_v1,[{attribute,1,
                                                             file,
                                                             {"src/redbug.erl",1}},
                                                  {attribute,9,module,redbug},
                                                  {attribute,11,export,[{help,0}]},
                                                  {attribute,13,export,[{unix,1}]},
                                                  {attribute,15,export,
                                                             [{start,1},{start,2},{start,3},{start,4},{start,5}]},
                                                  {attribute,16,export,[{stop,0}]},
                                                  {attribute,1,file,{"src/log.hrl",1}},
                                                  {function,17,'?log',2,
                                                            [{clause,17,[{var,17,...},{var,...}],[[{...}]],[{...}]},
                                                             {clause,18,[{var,...},{...}],[],[...]}]},
                                                  {attribute,19,file,{"src/redbug.erl",19}},
                                                  {attribute,22,record,
                                                             {cnf,[{record_field,24,{...},...},
                                                                   {record_field,25,...},
                                                                   {record_field,...},
                                                                   {...}|...]}},
                                                  {function,57,help,0,[{clause,57,[],...}]},
                                                  {function,123,unix,1,
                                                            [{clause,123,...},{clause,...},{...}|...]},
                                                  {function,146,to_term,1,[{clause,...},{...}]},
                                                  {function,154,maybe_halt,1,[{...}]},
                                                  {function,160,is_in_shell,0,[...]},
                                                  {function,167,stop,0,...},
                                                  {function,174,start,...},
                                                  {function,176,...},
                                                  {function,...},
                                                  {...}|...]}}]}}
    

    There you can find list, on which you could find tuples like {function, LineNumber, FunctionName, Arity, FunctionCodeAsList }. So by going trough this list and finding function you are looking for you can extract LineNumber.

    Still you need to take under account few things that might not work.

    • you are analyzing actual file from disc, so it need to be in you current directory. It has nothing to do if and what is loaded to your VM (what code version). So you might have to put a little work to actually find this .beam
    • files compiled without debug_info might fail in producing this abstract syntax tree. You need to decide if that is might be your case, and how would you like to handle this.
    • some beams might be encrypted, some might have other issues. You should read beam_lib module documentation just to get feel what you are dealing with.

    If you do come up with something, please do share. Happy hacking !