Tracing in Erlang with dbg — runtime_tools v2.3.1

Search documentation of runtime_tools

# Tracing in Erlang with dbg

View Source

The `dbg` module in Erlang provides a text-based interface for tracing function calls, processes, ports, and messages. It simplifies the use of the underlying `trace:process/4`, `trace:port/4`, and `trace:function/4` BIFs (Built-In Functions). This guide will walk you through the basics of using `dbg` for your Erlang applications.

This facility is useful for both quick debugging sessions in the shell and for more structured system testing, especially where other tools might have too much performance impact.

## Quick Start

To trace a call to a function with minimal fuss, call `dbg:c(Module, Name, Arguments)`. It starts a temporary trace receiver, enables all trace flags, and calls the designated function from a temporary process. For example, here is how to trace a call to `application:which_applications/0`:

    1> dbg:c(application, which_applications, []).
    (<0.92.0>) <0.45.0> ! {'$gen_call',{<0.92.0>,
                                        [alias|
                                         #Ref<0.0.11779.270031856.1478295555.230456>]},
                                       which_applications} (Timestamp: {1710,
                                                                        847802,
                                                                        479222})
    (<0.92.0>) out {gen,do_call,4} (Timestamp: {1710,847802,479231})
    (<0.92.0>) in {gen,do_call,4} (Timestamp: {1710,847802,479271})
    (<0.92.0>) << {[alias|#Ref<0.0.11779.270031856.1478295555.230456>],
                   [{stdlib,"ERTS  CXC 138 10","5.2.1"},
                    {kernel,"ERTS  CXC 138 10","9.2.2"}]} (Timestamp: {1710,
                                                                       847802,
                                                                       479274})
    [{stdlib,"ERTS  CXC 138 10","5.2.1"},
     {kernel,"ERTS  CXC 138 10","9.2.2"}]

In this example, four trace events are generated:

- A send event (`!`) for the sending of a request from the current process to the `application_controller` process.
- A schedule-out event (`out`) when the current process schedules out while waiting in a `receive` for the reply to arrive.
- A schedule-in event (`in`) when the current process is scheduled in when reply has arrived.
- A `receive` event (`<<`) when the current process retrieves the reply from the `application_controller` process.

The `dbg:c/4` function has a fourth argument for specifying the trace flags, (see flags).

## How-to Trace Systems

For more control, another way of tracing is to explicitly start a tracer and set the trace flags of your choice on the processes you want to trace. This is useful, when there is a complex system of processes, ports or nodes interacting where `dbg:c/3` is to blunt.

### Starting a Tracer (`dbg:tracer/0,2`)

First, you need to start a tracer process that will receive and display trace messages.

    1> dbg:tracer().  % Start the default trace message receiver
    {ok,<0.90.0>}     % <0.90.0> is the PID of the tracer process

This starts a server on the local node that will be the recipient of all trace messages. It uses a default handler that prints formatted trace messages to the Erlang shell.

If you need a custom tracer other than the default, you can create a tracer using `dbg:tracer(Type, Data)`:

- `Type = process`: `Data` is `{HandlerFun, InitialState}`. `HandlerFun` is a `fun/2` that takes the trace message and the previous state, returning a new state.
- `Type = port`: `Data` is a `fun/0` that returns a new trace port (e.g., created by `dbg:trace_port/2`).
- `Type = module`: `Data` is `{TracerModule, TracerState}` or a `fun/0` returning this, for use with `erl_tracer`.
- `Type = file`: `Data` is a filename where traces will be printed.

Note that only one tracer using this method can be started at a time. You can use trace sessions to start multiple tracers (see trace sessions).

### Tracing Processes and Ports (`dbg:p/1,2`)

Once the tracer is started, you can tell `dbg` which processes or ports to trace and what events to trace for them using `dbg:p(Item, Flags)`.

`Item` can be:

- `pid/0` or `port/0` - The corresponding process or port is traced. The process or port can be a remote process or port (on another Erlang node). The node must be in the list of traced nodes (see `dbg:n/1` and `dbg:tracer/3`).

- `all` - All processes and ports in the system as well as all processes and ports created hereafter are to be traced.

- `processes` - All processes in the system as well as all processes created hereafter are to be traced.

- `ports` - All ports in the system as well as all ports created hereafter are to be traced.

- `new` - All processes and ports created after the call are to be traced.

- `new_processes` - All processes created after the call are to be traced.

- `new_ports` - All ports created after the call are to be traced.

- `existing` - All existing processes and ports are traced.

- `existing_processes` - All existing processes are traced.

- `existing_ports` - All existing ports are traced.

- `atom/0` - The process or port with the corresponding registered name is traced. The process or port can on another Erlang node. The node must be in the list of traced nodes (see `dbg:n/1` and `dbg:tracer/3`).

- `integer/0` - The process `<0.Item.0>` is traced.

- `{X, Y, Z}` - The process `<X.Y.Z>` is traced.

- `string/0` - If the `Item` is a string "<X.Y.Z>" as returned from `pid_to_list/1`, the process `<X.Y.Z>` is traced.

`Flags` can be a single atom or a list of flags. The available flags are:

- `s (send)` - Traces the messages the process or port sends.

- `r (receive)` - Traces the messages the process or port receives.

- `m (messages)` - Traces the messages the process or port receives and sends.

- `c (call)` - Traces global function calls for the process according to the trace patterns set in the system (see `dbg:tp/2`).

- `p (procs)` - Traces process related events to the process.

- `ports` - Traces port related events to the port.

- `sos (set on spawn)` - Lets all processes created by the traced process inherit the trace flags of the traced process.

- `sol (set on link)` - Lets another process, `P2`, inherit the trace flags of the traced process whenever the traced process links to `P2`.

- `sofs (set on first spawn)` - This is the same as `sos`, but only for the first process spawned by the traced process.

- `sofl (set on first link)` - This is the same as `sol`, but only for the first call to `link/1` by the traced process.

- `all` - Sets all flags except `silent`.

- `clear` - Clears all flags.

- Other flags accepted by `trace:process/4` or `trace:port/4` (e.g., `timestamp`, `arity`, `return_to`).

`dbg:p(Item)` is a shorthand for `dbg:p(Item, [m])`.

This function returns either an error tuple or an `{ok, List}` tuple. The `List` consists of specifications of how many processes and ports that matched (in the case of a single pid exactly 1). The specification of matched processes is `{matched, Node, N}`. If the remote processor call (using `rpc`) to a remote node fails, the `rpc` error message is returned as the fourth element in the tuple and the number of matched processes is 0.

Example: Trace messages and process events for a specific process

    1> Pid = spawn(fun() -> receive {From,Msg} -> From ! Msg end end).
    <0.90.0>
    2> dbg:tracer().
    {ok,<0.92.0>}
    3> dbg:p(Pid, [m,procs]). % Trace messages and process events for Pid
    {ok,[{matched,nonode@nohost,1}]}
    4> Pid ! {self(),hello}.
    (<0.90.0>) << {<0.88.0>,hello} % Received by Pid
    {<0.88.0>,hello}
    (<0.90.0>) <0.88.0> ! hello    % Sent by Pid
    (<0.90.0>) exit normal         % Process event: Pid exited
    5> flush().
    Shell got hello
    ok

### Tracing Function Calls (`dbg:tp/2,3,4`, `dbg:tpl/2,3,4`)

To trace function calls, you need to:

1. Enable the `c`/`call` flag for the process(es) that will make the calls (using `dbg:p/2`).
2. Set a trace pattern for the function(s) you want to trace using `dbg:tp/2` or `dbg:tpl/2`.

`tp` stands for trace pattern (for exported functions by default). `tpl` stands for trace pattern local (for local or remote calls to local and exported functions).

The general syntax is `dbg:tp(ModuleOrMFA, MatchSpec)` or `dbg:tpl(ModuleOrMFA, MatchSpec)`.

`ModuleOrMFA` can be:

- `Module :: atom()`: Equivalent to `{Module, '_', '_'}` (trace all functions in the module).
- `{Module, Function, Arity}`: Trace specific function. `'_'` can be used as a wildcard.

Note that if the `Module` is specified as `'_'`, the `Function` and `Arity` parts must be specified as `'_'` as well. The same holds for the `Function` in relation to `Arity`.

`MatchSpec` defines what to trace and how, see match specifications.

- For simple call tracing, you can insert the empty list `[]`.
- The most common generic match specifications used can be found as built-in aliases.
  - `x` or `exception_trace`: Shows function names, parameters, return values, and exceptions. `[{'_',[],[{exception_trace}]}]`
  - `c` or `caller_trace`: Shows function names, parameters, and caller information. `[{'_',[],[{message,{caller_line}}]}]`
  - `cx` or `caller_exception_trace`: Combines `x` and `c`. `[{'_',[],[{exception_trace},{message,{caller_line}}]}]`

Example using built-in aliases:

    1> dbg:tracer().
    {ok,<0.90.0>}
    2> dbg:p(all, c). % Short for dbg:p(all, call)
    {ok,[{matched,nonode@nohost,49}]}
    3> dbg:tp(lists, seq, cx). % cx: call and exception tracing with caller info
    {ok,[{matched,nonode@nohost,2},{saved,cx}]}
    4> lists:seq(1, 3).
    (<0.88.0>) call lists:seq(1,3) ({erl_eval,do_apply,7,{"erl_eval.erl",904}})
    [1,2,3]
    (<0.88.0>) returned from lists:seq/2 -> [1,2,3]

Note that the caller info is the function that called lists:seq with file and line number.

### Tracing Message Events (`dbg:tpe/2`)

By default, if `send` or `receive` tracing is enabled for a process, all such events are traced. `dbg:tpe(Event, MatchSpec)` allows you to filter these events.

- `Event`: `send` or `'receive'`.
- `MatchSpec`: A match specifications.
  - For `send`: Matches on `[Receiver, Msg]`.
  - For `'receive'`: Matches on `[Node, Sender, Msg]`.

### Managing Trace Patterns

You can display, remove, save and load trace pattern matchspecifications, if any of these bullets are of interest, click the title to read the documentation.

- `dbg:ltp()` (List Trace Patterns): Lists all saved match specifications (from previous `tp` calls where a pattern was complex enough to be saved) and built-in aliases.
- `dbg:dtp()` (Delete Trace Patterns): Deletes all saved (not built-in) match specifications.
- `dbg:dtp(N)` (Delete Trace Pattern `N`): Deletes a specific saved pattern by its ID `N`.
- `dbg:wtp(FileName)` (Write Trace Patterns): Saves current (saved and built-in) match specifications to `FileName`.
- `dbg:rtp(FileName)` (Read Trace Patterns): Reads match specifications from `FileName` and merges them.

To stop tracing specific functions, you clear their trace patterns.

- `dbg:ctp(ModuleOrMFA)`: Clears both global and local trace patterns.
  - `ctp()`: Clears all trace patterns for all functions.
  - `ctp(Module)`: Clears patterns for all functions in `Module`.
  - `ctp(Module, Function)` / `ctp(Module, Function, Arity)`: More specific.
- `dbg:ctpl(ModuleOrMFA)`: Clears only local trace patterns (set by `tpl`).
- `dbg:ctpg(ModuleOrMFA)`: Clears only global trace patterns (set by `tp`).
- `dbg:ctpe(Event)`: Clears the match specification for `send` or `'receive'`, reverting to tracing all such events if the flag is set.

## Match Specifications

Match Specifications are a powerful mini-language used to define conditions for tracing and actions to take. The `dbg:tp/2`, `dbg:tpl/2` and `dbg:tpe/2` functions accept them. For a description of the format for the `MatchSpec` argument, see Match Specifications in Erlang, which explains the general match specification language. For most users, `dbg:fun2ms/1` explained below will do.

A match specification is a list of tuples: `[{MatchHead, Guard, BodyActions}]`.

- `MatchHead`: Patterns to match function arguments. `'_'` matches anything. `'$1'` is a variable.
- `Guard`: Conditions that must be true.
- `BodyActions`: Actions like `{return_trace}` (trace return value), `{message, term()}` (include extra info), `{set_seq_token, ...}`.

### Creating Match Specifications with `dbg:fun2ms/1`

You can use `dbg:fun2ms/1` to translate a literal Erlang fun into a match specification. This often feels more natural than writing the raw match spec. The fun must take a single list argument (matching the function arguments) and its body can use guard expressions and special tracing functions. The parse transform module `ms_transform` must be enabled. The easiest way to enable it is by adding the following line to the source file: `-include_lib("stdlib/include/ms_transform.hrl").` In the shell its already enabled.

The head of the fun must be a single pattern that matches a list. That pattern will be used to match the arguments for the call:

    1> dbg:fun2ms(fun([_,_]) -> true end). % Matches a function with two arguments
    [{['_','_'],[],[true]}]
    2> dbg:fun2ms(fun([A]) when is_atom(A) -> return_trace() end).
    [{['$1'],[{is_atom,'$1'}],[{return_trace}]}]

The first match specification matches when a function having two arguments is called. The second matches when a function, taking one atom as an argument, is called.

## Trace Sessions

To avoid interference between different tracing activities, you can create isolated `dbg` sessions.

First you create a session with `dbg:session_create(Name)` where the name is an atom, a `session/0` is returned. Several sessions may have the same name.

When you have the `session/0`, you use `dbg:session(Session, Fun)`. This function runs `dbg` commands within `Fun` using the specified session.

Any `dbg` function that is called with in the provided fun will use the `session/0` provided instead of the default `dbg` session. This means that the tracing will be isolated from other tracing users on the system.

When you no longer need the session, use `dbg:session_destroy(Session)`.

Example:

    1> S = dbg:session_create(my_session).
    <0.91.0>
    2> dbg:session(S, fun() -> dbg:tracer(), dbg:p(all,c), dbg:tp(lists,seq,x) end).
    {ok,[{matched,nonode@nohost,2},{saved,x}]}
    3> lists:seq(1, 10).
    (<0.89.0>) call lists:seq(1,10)
    (<0.89.0>) returned from lists:seq/2 -> [1,2,3,4,5,6,7,8,9,10]
    [1,2,3,4,5,6,7,8,9,10]
    4> dbg:session_destroy(S).
    ok

The state of the `session/0` is preserved in between `dbg:session/2` calls, so you can call `dbg:session/2` multiple times when debugging you application.

Example:

    1> S = dbg:session_create(my_session).
    <0.91.0>
    %% Setup the initial traces
    2> dbg:session(S, fun() -> dbg:tracer(), dbg:p(self(),c), dbg:tp(lists,seq,x) end).
    {ok,[{matched,nonode@nohost,2},{saved,x}]}
    3> lists:seq(1, 3).
    (<0.89.0>) call lists:seq(1,3)
    (<0.89.0>) returned from lists:seq/2 -> [1,2,3]
    [1,2,3]
    %% Add an additional trace pattern
    4> dbg:session(S, fun() -> dbg:tpl(lists,seq_loop,x) end).
    ok
    5> lists:seq(1, 3).
    (<0.89.0>) call lists:seq(1,3)
    (<0.89.0>) call lists:seq_loop(3,3,[])
    (<0.89.0>) call lists:seq_loop(1,1,[2,3])
    (<0.89.0>) returned from lists:seq_loop/3 -> [1,2,3]
    (<0.89.0>) returned from lists:seq_loop/3 -> [1,2,3]
    (<0.89.0>) returned from lists:seq/2 -> [1,2,3]
    [1,2,3]
    6> dbg:session_destroy(S).
    ok

## Trace on Remote Nodes

The `dbg` server keeps a list of nodes where tracing should be performed. Whenever a `dbg:tp/2` call or a `dbg:p/2` call is made, it is executed for all nodes in this list including the local node (except for `dbg:p/2` with a specific `pid/0` or `port/0` as first argument, in which case the command is executed only on the node where the designated process or port resides).

`dbg:n(Nodename)`: When this function is called, it starts a tracer process on the remote node, which will send all trace messages to the tracer process on the local node (via the Erlang distribution). If no tracer process is running on the local node, the error reason `no_local_tracer` is returned. The tracer process on the local node must be started with the `dbg:tracer/0,2` function.

If `Nodename` is the local node, the error reason `cant_add_local_node` is returned. The function will also return an error if the node `Nodename` is not reachable.

If a trace port (see `dbg:trace_port/2`) is running on the local node, remote nodes cannot be traced with a tracer process. The error reason `cant_trace_remote_pid_to_local_port` is returned. However, a trace port can be started on the remote node with the `dbg:tracer/3` function.

`dbg:tracer(Nodename, Type, Data)`: An independent tracer is started on the node (`Nodename`) and the node is added to the list of traced nodes.

#### Note

`dbg:tracer(Nodename, Type, Data)` is not equivalent to `dbg:n/1`. While `dbg:n/1` starts a process tracer which redirects all trace information to a process tracer on the local node (that is, the trace control node), `dbg:tracer/3` starts any type of tracer, independent of the type of tracer on the trace control node.

### Managing nodes

`dbg` can trace processes and functions on other Erlang nodes in a distributed system.

- `dbg:cn(Nodename)` (Clear Node): Removes `Nodename` from the list. Tracing already active on that node continues but new global `tp/p` calls won't affect it.
- `dbg:ln()` (List Nodes): Shows the list of currently traced nodes.

## Trace Ports for Lower Overhead

For high-volume tracing, sending messages to an Erlang process can be too slow. A trace port is an Erlang port to a dynamically linked-in driver that handles trace messages directly, without the overhead of sending them as messages to an Erlang process. Using a trace port significantly lowers the overhead imposed by tracing.

### Creating Trace Ports (`dbg:trace_port/2`)

`dbg:trace_port(Type, Parameters)` returns a `fun/0` that, when called, creates and returns a port. This fun is then passed as the second argument to `dbg:tracer(port, Fun)`.

Two trace drivers are available: the `file` and the `ip` trace drivers.

- `file`: Writes trace messages to binary file(s).
  - `Parameters`: `Filename` or a wrap files specification: `{Filename, wrap, Suffix}` `{Filename, wrap, Suffix, WrapSize}` `{Filename, wrap, Suffix, WrapSize, WrapCnt}` `{Filename, wrap, Suffix, {time, WrapTime}, WrapCnt}` Wrap files limit disk space by rotating through `WrapCnt` files, each up to `WrapSize` or open for `WrapTime`.
- `ip`: Opens a TCP/IP listening port. A client connects to receive trace messages.
  - `Parameters`: `PortNumber` or `{PortNumber, QueSize}`.

The `file` trace driver expects a filename or a wrap files specification as parameter. A file is written with a high degree of buffering, which is why there is no guarantee that all are saved in the file in case of a system crash.

A wrap files specification is used to limit the disk space consumed by the trace. The trace is written to a limited number of files each with a limited size. The actual filenames are `Filename ++ SeqCnt ++ Suffix`, where `SeqCnt` counts as a decimal string from `0` to `WrapCnt` and then around again from `0`. When a trace term written to the current file makes it longer than `WrapSize`, that file is closed, and if the number of files in this wrap trace is as many as `WrapCnt` the oldest file is deleted, and a new file is opened to become the current. Thus, when a wrap trace has been stopped, there are at most `WrapCnt` trace files saved with a size of at least `WrapSize` (but not much larger), except for the last file that might even be empty. The default values are `WrapSize = 128*1024` and `WrapCnt = 8`.

The `SeqCnt` values in the filenames are all in the range `0` through `WrapCnt` with a gap in the circular sequence. The gap is needed to find the end of the trace.

If the `WrapSize` is specified as `{time, WrapTime}`, the current file is closed when it has been open more than `WrapTime` milliseconds, regardless of it being empty or not.

The `ip` trace driver has a queue of `QueSize` messages waiting to be delivered. If the driver cannot deliver messages as fast as they are produced by the runtime system, a special message is sent, which indicates how many messages that are dropped. That message will arrive at the handler function specified in `dbg:trace_client/3` as the tuple `{drop, N}` where `N` is the number of consecutive messages dropped. In case of heavy tracing, drops are likely to occur, and they surely occur if no client is reading the trace messages. The default value of `QueSize` is 200.

### Reading Trace Port Data (`dbg:trace_client/2,3`)

`dbg:trace_client(Type, Parameters)` Starts a trace client that reads the output created by a trace port driver (see `dbg:trace_port/2`) and handles it in mostly the same way as a tracer process created by the `dbg:tracer/0` function. `dbg:trace_client(Type, Parameters, HandlerSpec)` This function works exactly as `dbg:trace_client/2`, but allows you to write your own handler function.

If `Type` is `file`, the client reads all trace messages stored in the file named `Filename` or specified by `WrapFilesSpec` (must be the same as used when creating the trace) and lets the default handler function format the messages on the console. This is one way to interpret the data stored in a file by the file trace port driver.

If `Type` is `follow_file`, the client behaves as in the `file` case, but keeps trying to read (and process) more data from the file until stopped by `dbg:stop_trace_client/1`. `WrapFilesSpec` is not allowed as second argument for this `Type`.

If `Type` is `ip`, the client connects to the TCP/IP port `PortNumber` on the host `Hostname`, from where it reads trace messages until the TCP/IP connection is closed. If no `Hostname` is specified, the local host is assumed.

The handler function works mostly as the one described in `dbg:tracer/2`, but must also be prepared to handle trace messages of the form `{drop, N}`, where `N` is the number of dropped messages. This pseudo trace message will only occur if the `ip` trace driver is used.

For trace type `file`, the pseudo trace message `end_of_trace` will appear at the end of the trace. The return value from the handler function is in this case ignored.

Example: Using an IP trace port and connecting to it from another node As an example, one can let trace messages be sent over the network to another Erlang node (preferably not distributed), where the formatting occurs.

On the node `stack` there exists an Erlang node `ant@stack`. In the shell, type the following:

    ant@stack> dbg:tracer(port, dbg:trace_port(ip, 4711)).
    <0.17.0>
    ant@stack> dbg:p(self(), send).
    {ok,1}

All trace messages are now sent to the trace port driver, which in turn listens for connections on the TCP/IP port 4711. If we want to see the messages on another node, preferably on another host, we do like this:

    1> dbg:trace_client(ip, {"stack", 4711}).
    <0.42.0>

If we now send a message from the shell on the node `ant@stack`, where all sends from the shell are traced:

    ant@stack> self() ! hello.
    hello

The following will appear at the console on the node that started the trace client:

    (<0.23.0>) <0.23.0> ! hello
    (<0.23.0>) <0.22.0> ! {shell_rep,<0.23.0>,{value,hello,[],[]}}

The last line is generated due to internal message passing in the Erlang shell. The pids will vary.

### Controlling Trace Ports

- `dbg:flush_trace_port()` / `dbg:flush_trace_port(Node)`: Flushes internal buffers of the trace port driver on the local/specified node (currently for `file` driver).
- `dbg:trace_port_control(Operation)` / `dbg:trace_port_control(Node, Operation)`:
  - `Operation = flush`: Same as above.
  - `Operation = get_listen_port`: For `ip` driver, returns `{ok, IpPortNumber}`.
- `dbg:stop_trace_client(Pid)`: Shuts down the trace client `Pid`.

## Sequential Tracing

The `dbg` module is primarily targeted towards tracing through the `trace:process/4` function. It is sometimes desired to trace messages in a more delicate way, which can be done with the help of the `seq_trace` module.

`seq_trace` implements sequential tracing (known in the AXE10 world, and sometimes called "forlopp tracing"). `dbg` can interpret messages generated from `seq_trace` and the same tracer function for both types of tracing can be used. The `seq_trace` messages can also be sent to a trace port for further analysis.

As a match specification can turn on sequential tracing, the combination of `dbg` and `seq_trace` can be powerful. This brief example shows a session where sequential tracing is used to trace the `dbg` module and the trace itself:

    1> dbg:tracer().
    {ok,<0.30.0>}
    2> {ok, Tracer} = dbg:get_tracer().
    {ok,<0.31.0>}
    3> seq_trace:set_system_tracer(Tracer).
    false
    4> dbg:tp(dbg, get_tracer, 0, [{[],[],[{set_seq_token, send, true}]}]).
    {ok,[{matched,nonode@nohost,1},{saved,1}]}
    5> dbg:p(all,call).
    {ok,[{matched,nonode@nohost,22}]}
    6> dbg:get_tracer(), seq_trace:set_token([]).
    (<0.25.0>) call dbg:get_tracer()
    SeqTrace [0]: (<0.25.0>) <0.30.0> ! {<0.25.0>,get_tracer} [Serial: {2,4}]
    SeqTrace [0]: (<0.30.0>) <0.25.0> ! {dbg,{ok,<0.31.0>}} [Serial: {4,5}]
    {1,0,5,<0.30.0>,4}

This session sets the system_tracer to the same process as the ordinary tracer process (i. e. <0.31.0>) and sets the trace pattern for the function `dbg:get_tracer` to one that has the action of setting a sequential token. When the function is called by a traced process (all processes are traced in this case), the process gets "contaminated" by the token and `seq_trace` messages are sent both for the server request and the response. The `seq_trace:set_token([])` after the call clears the `seq_trace` token, which is why no messages are sent when the answer propagates via the shell to the console port. Otherwise the output would have been more noisy.

## Avoiding Overloads

Tracing can generate a significant amount of data, potentially overwhelming your system if not managed carefully. To prevent performance degradation or even crashes, consider these strategies:

Time-Limited Tracing: One effective method is to automatically stop tracing after a set period.

    dbg:tracer(), dbg:p(all,[c]), dbg:tpl(lists,map,x), timer:sleep(1000), dbg:stop().

Be Specific:

Processes: Instead of `dbg:p(all, Flags).`, try to pinpoint specific processes if you know which ones are relevant: `dbg:p(Pid, Flags)`. You can also trace newly spawned processes with `dbg:p(new, Flags).`.

Modules & Functions: Rather than tracing all calls, narrow down to specific modules and functions with `dbg:tp/2` or `dbg:tpl/2`

Use Match Specifications: For example, to only trace calls to `my_module:my_function/1` when the first argument is the atom error:

    dbg:tpl(my_module, my_function, dbg:fun2ms(fun([error])->true end)).

Limit Trace Flags: Only enable the flags essential for your debugging task (e.g., m for message passing, c for function calls).

Trace to File for High Volumes: If you anticipate a large volume of trace data, tracing directly to the console can become a bottleneck. Consider tracing to a file instead, see trace ports.

    dbg:tracer(port, {file, "trace_output.log"}),
    % ... your other dbg commands ...
    timer:sleep(5000),
    dbg:stop().

## Avoiding Deadlocks

When tracing function calls on a group leader process (an I/O process), there is risk of causing a deadlock. This will happen if a group leader process generates a trace message and the tracer process, by calling the trace handler function, sends an I/O request to the same group leader. The problem can only occur if the trace handler prints to the tty using an `io` function such as `format/2`. Note that when `dbg:p(all, call)` is called, IO processes are also traced. Here is an example:

    %% Using a default line editing shell
    1> dbg:tracer(process, {fun(Msg,_) -> io:format("~p~n", [Msg]), 0 end, 0}).
    {ok,<0.37.0>}
    2> dbg:p(all, [call]).
    {ok,[{matched,nonode@nohost,25}]}
    3> dbg:tp(mymod,[{'_',[],[]}]).
    {ok,[{matched,nonode@nohost,0},{saved,1}]}
    4> mymod: % TAB pressed here
    %% -- Deadlock --

Here is another example:

    %% Using a shell without line editing (oldshell)
    1> dbg:tracer(process).
    {ok,<0.31.0>}
    2> dbg:p(all, [call]).
    {ok,[{matched,nonode@nohost,25}]}
    3> dbg:tp(lists,[{'_',[],[]}]).
    {ok,[{matched,nonode@nohost,0},{saved,1}]}
    % -- Deadlock --

The reason we get a deadlock in the first example is because when TAB is pressed to expand the function name, the group leader (which handles character input) calls `mymod:module_info()`. This generates a trace message which, in turn, causes the tracer process to send an IO request to the group leader (by calling `io:format/2`). We end up in a deadlock.

In the second example we use the default trace handler function. This handler prints to the tty by sending IO requests to the `user` process. When Erlang is started in the oldshell mode, the shell process will have `user` as its group leader and so will the tracer process in this example. Since `user` calls functions in `lists` we end up in a deadlock as soon as the first IO request is sent.

Here are a few suggestions for avoiding deadlock:

- Do not trace the group leader of the tracer process. If tracing has been switched on for all processes, call `dbg:p(TracerGLPid, clear)` to stop tracing the group leader (`TracerGLPid`). `process_info(TracerPid, group_leader)` tells you which process this is (`TracerPid` is returned from `dbg:get_tracer/0`).
- Do not trace the `user` process if using the default trace handler function.
- In your own trace handler function, call `erlang:display/1` instead of an `io` function or, if `user` is not used as group leader, print to `user` instead of the default group leader. Example: `io:format(user, Str, Args)`.

## Getting Information and Help

- `dbg:i()` (Information): Displays information about all currently traced processes and ports and their active trace flags.
- `dbg:h()` (Help): Lists available help items.
- `dbg:h(Item :: atom())`: Gives brief help for a specific `dbg` function or concept (e.g., `dbg:h(tp)`).
- `dbg:get_tracer()` / `dbg:get_tracer(Node)`: Returns the process, port, or tracer module handling traces on the local/specified node.
- Consult the dbg module documentation.

← Previous Page SystemTap and Erlang/OTP