Search code examples
debuggingerlangrabbitmqrabbitmq-exchange

How to attach erlang dbg to a running process?


How could I attach a debugger to a running erlang process (rabbitmq)? I have the source code of the same rabbit version that's running. I would like to set a breakpoint on a source line, and attach a debugger to the running rabbit instance. I'm not sure if erlang requires debug symbols async_dirty.

In a perfect world, I would like to be able to do that both locally and remotely.


Solution

  • From what you're saying, you don't really need to run a debugger. The Erlang VM's concurrency model doesn't fit well with the concept of stop-everything-and-inspect-style debugging.

    On the other hand, the VM has great, built-in tracing capabilities. The dbg module is where they are all exposed, but that module's interface is quite difficult to use, especially if you're a beginner. I'd recommend using recon_trace to get a view into what's going on with your process: http://ferd.github.io/recon/recon_trace.html.

    If you don't feel like installing recon, start your program from the Erlang shell, and in that shell, type:

    %enable tracing capabilities
    1> dbg:tracer().  
    
    % Trace Pattern Local-scope 
    % (tell the tracer to trace every call in YourModule, even unexported functions).
    2> dbg:tpl(YourModule, x). 
    
    % Tell dbg to print calls from all processes calling your module.
    3> dbg:p(all,call). 
    
    % Run your traced module
    4> YourModule:SomeFun().  
    
    % You should see nice(?) traces of inputs, outputs, and
    % exceptions in your shell
    

    Check out the following session, where I fumble around not knowing how to use the queue module:

    Eshell V6.3  (abort with ^G)
    1> dbg:tracer(), dbg:tpl(queue, x), dbg:p(all, call).
    {ok,[{matched,nonode@nohost,26}]}
    2> X = queue:new().
    (<0.33.0>) call queue:new()
    (<0.33.0>) returned from queue:new/0 -> {[],[]}
    {[],[]}
    3> X = queue:cons(1).
    ** exception error: undefined function queue:cons/1
    4> X = queue:cons(X,1).
    (<0.39.0>) call queue:cons({[],[]},1)
    (<0.39.0>) call queue:in_r({[],[]},1)
    (<0.39.0>) exception_from {queue,in_r,2} {error,badarg}
    (<0.39.0>) exception_from {queue,cons,2} {error,badarg}
    ** exception error: bad argument
         in function  queue:in_r/2
            called as queue:in_r({[],[]},1)
    5> X = queue:cons(1,X).
    (<0.41.0>) call queue:cons(1,{[],[]})
    (<0.41.0>) call queue:in_r(1,{[],[]})
    (<0.41.0>) returned from queue:in_r/2 -> {[],[1]}
    (<0.41.0>) returned from queue:cons/2 -> {[],[1]}
    ** exception error: no match of right hand side value {[],[1]}
    6> X1 = queue:cons(1,X).
    (<0.43.0>) call queue:cons(1,{[],[]})
    (<0.43.0>) call queue:in_r(1,{[],[]})
    (<0.43.0>) returned from queue:in_r/2 -> {[],[1]}
    (<0.43.0>) returned from queue:cons/2 -> {[],[1]}
    {[],[1]}
    

    Hope this helps to get you started.

    If you want to see how the Erlang wizards do it, watch Mats Cronqvist's talk "Taking the printf out of printf debugging".