Tracing child processes with redbug

Roberto Aloi
About Erlang
Published in
2 min readMar 30, 2018

Redbug is a tracing and debugging utility which allows you to troubleshoot your Erlang releases in a simple way. Redbug makes tracing Erlang code a smooth and pleasant experience by leveraging the Erlang tracing functionalities and combining them with a user-friendly API. I extensively wrote about Redbug already, so I won’t repeat myself here.

What I want to share, instead, is an interesting feature that has recently been included in redbug, but went almost un-noticed by the mass. This is probably due to the fact that, some months ago, redbug sneakily moved away from the eper project to its own repo on GitHub. The redbug version inside eper is apparently not actively maintained anymore.

Long story short, redbug now allows you to restrict tracing not just to a given set of processes, but also to their children. It does so by leveraging the set_on_spawn Erlang tracing flag which ensures that processes created by the set of traced processes are also traced.

This is extremely useful in situations where, for example, you want to debug a chain of function calls in a production system under heavy load. In a scenario where the functions that you want to trace are executed by multiple processes spawned by the initial one, restricting tracing to a set of pids (using the procs option) was not an option, since the processes that you wanted to trace didn’t exist yet. The only option you were left with was to trace all processes in the system. In a system under heavy load, this typically required to increase the number of traced messages (using the msgs option) to a very high number, to dump the results of the tracing session to a file (using the print_file option) and to manually go through the dumped file, in search of interesting entries.

Today life is much easier, thanks to the trace_child option. Let’s see it in action.

1> l(redbug).
{module,redbug}
2> redbug:start("maps",[{procs,self()}]).
{1,30}
3> spawn(fun()->maps:new()end).
<0.65.0>
redbug done, timeout - 0
4> redbug:start("maps",[{procs,self()},trace_child]).
{1,30}
5> spawn(fun()->maps:new()end).
<0.73.0>
% 18:24:19 <0.73.0>(dead)
% maps:new()

After ensuring the redbug module is loaded (1), we start a tracing session where we trace all function calls to the maps module and we limit the set of traced processes to the current one (2). We then spawn a process which will invoke the maps:new/0 function (3). Since the trace_children option is not set, the function call is not traced and the redbug session terminates after the default timeout is reached. We then repeat the experiment, but this time we enable the trace_child option (4,5). This time the function call to the maps module by the spawned process (pid <0.73.0>) is displayed.

Happy tracing!

--

--