traceerlang-otpdbg

No output from erlang tracer


I've got a module my_api with a function which is callback for cowboy's requests handle/2, So when I make some http requests like this:

curl http://localhost/test

to my application this function is called and it's working correctly because I get a response in the terminal.

But in another terminal I attach to my application with remsh and try to trace calls to that function with a dbg module like this:

dbg:tracer().
dbg:tp(my_api, handle, 2, []).
dbg:p(all, c).

I expected that after in another terminal I make a http request to my api, the function my_api:handle/2 is called and I get some info about this call (at least function arguments) in the attached to the node terminal but I get nothing in there. What am I missing?


Solution

  • When you call dbg:tracer/0, a tracer of type process is started with a message handler that sends all trace messages to the user I/O device. Your remote shell's group leader is independent of the user I/O device, so your shell doesn't receive the output sent to user.

    One approach to allow you to see trace output is to set up a trace port on the server and a trace client in a separate node. If you want traces from node foo, first remsh to it:

    $ erl -sname bar -remsh foo
    

    Then set up a trace port. Here, we set up a TCP/IP trace port on host port 50000 (use any port you like as long as it's available to you):

    1> dbg:tracer(port, dbg:trace_port(ip, 50000)).
    

    Next, set up the trace parameters as you did before:

    2> dbg:tp(my_api, handle, 2, []).
    {ok, ...}
    3> dbg:p(all, c).
    {ok, ...}
    

    Then exit the remsh, and start a node without remsh:

    $ erl -sname bar
    

    On this node, start a TCP/IP trace client attached to host port 50000:

    1> dbg:trace_client(ip, {"localhost", 50000}).
    

    This shell will now receive dbg trace messages from foo. Here, we used "localhost" as the hostname since this node is running on the same host as the server node, but you'll need to use a different hostname if your client is running on a separate host.

    Another approach, which is easier but relies on an undocumented function and so might break in the future, is to remsh to the node to be traced as you originally did but then use dbg:tracer/2 to send dbg output to your remote shell's group leader:

    1> dbg:tracer(process, {fun dbg:dhandler/2, group_leader()}).
    {ok, ...}
    2> dbg:tp(my_api, handle, 2, []).
    {ok, ...}
    3> dbg:p(all, c).
    {ok, ...}
    

    Since this relies on the dbg:dhandler/2 function, which is exported but undocumented, there's no guarantee it will always work.

    Lastly, since you're tracing all processes, please pay attention to the potential problems described in the dbg man page, and always be sure to call dbg:stop_clear(). when you're finished tracing.