erl_tracer(3erl) Erlang Module Definition erl_tracer(3erl)
NAME
erl_tracer - Erlang tracer behavior.
DESCRIPTION
This behavior module implements the back end of the Erlang tracing sys-
tem. The functions in this module are called whenever a trace probe is
triggered. Both the enabled and trace functions are called in the con-
text of the entity that triggered the trace probe. This means that the
overhead by having the tracing enabled is greatly effected by how much
time is spent in these functions. So, do as little work as possible in
these functions.
Note:
All functions in this behavior must be implemented as NIFs. This limi-
tation can be removed in a future releases. An example tracer module
NIF implementation is provided at the end of this page.
Warning:
Do not send messages or issue port commands to the Tracee in any of the
callbacks. This is not allowed and can cause all sorts of strange be-
havior, including, but not limited to, infinite recursions.
DATA TYPES
trace_tag_call() =
call | return_to | return_from | exception_from
trace_tag_gc() =
gc_minor_start | gc_minor_end | gc_major_start | gc_major_end
trace_tag_ports() =
open | closed | link | unlink | getting_linked |
getting_unlinked
trace_tag_procs() =
spawn | spawned | exit | link | unlink | getting_linked |
getting_unlinked | register | unregister
trace_tag_receive() = 'receive'
trace_tag_running_ports() =
in | out | in_exiting | out_exiting | out_exited
trace_tag_running_procs() =
in | out | in_exiting | out_exiting | out_exited
trace_tag_send() = send | send_to_non_existing_process
trace_tag() =
trace_tag_send() |
trace_tag_receive() |
trace_tag_call() |
trace_tag_procs() |
trace_tag_ports() |
trace_tag_running_procs() |
trace_tag_running_ports() |
trace_tag_gc()
The different trace tags that the tracer is called with. Each
trace tag is described in detail in Module:trace/5.
tracee() = port() | pid() | undefined
The process or port that the trace belongs to.
trace_opts() =
#{extra => term(),
match_spec_result => term(),
scheduler_id => integer() >= 0,
timestamp =>
timestamp | cpu_timestamp | monotonic | strict_monotonic}
The options for the tracee:
timestamp:
If set the tracer has been requested to include a time
stamp.
extra:
If set the tracepoint has included additional data about the
trace event. What the additional data is depends on which
TraceTag has been triggered. The extra trace data corre-
sponds to the fifth element in the trace tuples described in
erlang:trace/3.
match_spec_result:
If set the tracer has been requested to include the output
of a match specification that was run.
scheduler_id:
If set the scheduler id is to be included by the tracer.
tracer_state() = term()
The state specified when calling erlang:trace(PidPort-
Spec,true,[{tracer,Module,TracerState}]). The tracer state is an
immutable value that is passed to erl_tracer callbacks and is to
contain all the data that is needed to generate the trace event.
CALLBACK FUNCTIONS
The following functions are to be exported from an erl_tracer callback
module:
Module:enabled/3:
Mandatory
Module:trace/5:
Mandatory
Module:enabled_call/3:
Optional
Module:trace_call/5:
Optional
Module:enabled_garbage_collection/3:
Optional
Module:trace_garbage_collection/5:
Optional
Module:enabled_ports/3:
Optional
Module:trace_ports/5:
Optional
Module:enabled_procs/3:
Optional
Module:trace_procs/5:
Optional
Module:enabled_receive/3:
Optional
Module:trace_receive/5:
Optional
Module:enabled_running_ports/3:
Optional
Module:trace_running_ports/5:
Optional
Module:enabled_running_procs/3:
Optional
Module:trace_running_procs/5:
Optional
Module:enabled_send/3:
Optional
Module:trace_send/5:
Optional
EXPORTS
Module:enabled(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag() | trace_status
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint is triggered. It
allows the tracer to decide whether a trace is to be generated
or not. This check is made as early as possible to limit the
amount of overhead associated with tracing. If trace is re-
turned, the necessary trace data is created and the trace call-
back of the tracer is called. If discard is returned, this trace
call is discarded and no call to trace is done.
trace_status is a special type of TraceTag, which is used to
check if the tracer is still to be active. It is called in mul-
tiple scenarios, but most significantly it is used when tracing
is started using this tracer. If remove is returned when the
trace_status is checked, the tracer is removed from the tracee.
This function can be called multiple times per tracepoint, so it
is important that it is both fast and without side effects.
Module:enabled_call(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_call()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
call | return_to is triggered.
If enabled_call/3 is undefined, Module:enabled/3 is called in-
stead.
Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Re-
sult
Types:
TraceTag = trace_tag_gc()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
garbage_collection is triggered.
If enabled_garbage_collection/3 is undefined, Module:enabled/3
is called instead.
Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_ports()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
ports is triggered.
If enabled_ports/3 is undefined, Module:enabled/3 is called in-
stead.
Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_procs()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
procs is triggered.
If enabled_procs/3 is undefined, Module:enabled/3 is called in-
stead.
Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_receive()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
'receive' is triggered.
If enabled_receive/3 is undefined, Module:enabled/3 is called
instead.
Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_running_ports()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
running_ports is triggered.
If enabled_running_ports/3 is undefined, Module:enabled/3 is
called instead.
Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_running_procs()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
running_procs | running is triggered.
If enabled_running_procs/3 is undefined, Module:enabled/3 is
called instead.
Module:enabled_send(TraceTag, TracerState, Tracee) -> Result
Types:
TraceTag = trace_tag_send()
TracerState = term()
Tracee = tracee()
Result = trace | discard | remove
This callback is called whenever a tracepoint with trace flag
send is triggered.
If enabled_send/3 is undefined, Module:enabled/3 is called in-
stead.
Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
Types:
TraceTag = trace_tag()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled/3 callback returned trace. In it any side effects
needed by the tracer are to be done. The tracepoint payload is
located in the TraceTerm. The content of the TraceTerm depends
on which TraceTag is triggered. TraceTerm corresponds to the
fourth element in the trace tuples described in erlang:trace/3.
If the trace tuple has five elements, the fifth element will be
sent as the extra value in the Opts maps.
Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) -> Re-
sult
Types:
TracerState = term()
Label = term()
SeqTraceInfo = term()
Opts = trace_opts()
Result = ok
The TraceTag seq_trace is handled slightly differently. There is
no Tracee for seq_trace, instead the Label associated with the
seq_trace event is specified.
For more information on what Label and SeqTraceInfo can be, see
seq_trace(3erl).
Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
Result
Types:
TraceTag = trace_tag_call()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_call/3 callback returned trace.
If trace_call/5 is undefined, Module:trace/5 is called instead.
Module:trace_garbage_collection(TraceTag, TracerState, Tracee,
TraceTerm, Opts) -> Result
Types:
TraceTag = trace_tag_gc()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_garbage_collection/3 callback returned trace.
If trace_garbage_collection/5 is undefined, Module:trace/5 is
called instead.
Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
Result
Types:
TraceTag = trace_tag()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_ports/3 callback returned trace.
If trace_ports/5 is undefined, Module:trace/5 is called instead.
Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
Result
Types:
TraceTag = trace_tag()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_procs/3 callback returned trace.
If trace_procs/5 is undefined, Module:trace/5 is called instead.
Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
Result
Types:
TraceTag = trace_tag_receive()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_receive/3 callback returned trace.
If trace_receive/5 is undefined, Module:trace/5 is called in-
stead.
Module:trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm,
Opts) -> Result
Types:
TraceTag = trace_tag_running_ports()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_running_ports/3 callback returned trace.
If trace_running_ports/5 is undefined, Module:trace/5 is called
instead.
Module:trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm,
Opts) -> Result
Types:
TraceTag = trace_tag_running_procs()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_running_procs/3 callback returned trace.
If trace_running_procs/5 is undefined, Module:trace/5 is called
instead.
Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) ->
Result
Types:
TraceTag = trace_tag_send()
TracerState = term()
Tracee = tracee()
TraceTerm = term()
Opts = trace_opts()
Result = ok
This callback is called when a tracepoint is triggered and the
Module:enabled_send/3 callback returned trace.
If trace_send/5 is undefined, Module:trace/5 is called instead.
ERL TRACER MODULE EXAMPLE
In this example, a tracer module with a NIF back end sends a message
for each send trace tag containing only the sender and receiver. Using
this tracer module, a much more lightweight message tracer is used,
which only records who sent messages to who.
The following is an example session using it on Linux:
$ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c
$ erl
Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0 (abort with ^G)
1> c(erl_msg_tracer), erl_msg_tracer:load().
ok
2> Tracer = spawn(fun F() -> receive M -> io:format("~p~n",[M]), F() end end).
<0.37.0>
3> erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]).
0
{trace,<0.39.0>,<0.27.0>}
4> {ok, D} = file:open("/tmp/tmp.data",[write]).
{trace,#Port<0.486>,<0.40.0>}
{trace,<0.40.0>,<0.21.0>}
{trace,#Port<0.487>,<0.4.0>}
{trace,#Port<0.488>,<0.4.0>}
{trace,#Port<0.489>,<0.4.0>}
{trace,#Port<0.490>,<0.4.0>}
{ok,<0.40.0>}
{trace,<0.41.0>,<0.27.0>}
5>
erl_msg_tracer.erl:
-module(erl_msg_tracer).
-export([enabled/3, trace/5, load/0]).
load() ->
erlang:load_nif("erl_msg_tracer", []).
enabled(_, _, _) ->
error.
trace(_, _, _, _, _) ->
error.
erl_msg_tracer.c:
#include <erl_nif.h>
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ErlNifFunc nif_funcs[] = {
{"enabled", 3, enabled},
{"trace", 5, trace}
};
ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
*priv_data = NULL;
return 0;
}
static void unload(ErlNifEnv* env, void* priv_data)
{
}
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
ERL_NIF_TERM load_info)
{
if (*old_priv_data != NULL || *priv_data != NULL) {
return -1; /* Don't know how to do that */
}
if (load(env, priv_data, load_info)) {
return -1;
}
return 0;
}
/*
* argv[0]: TraceTag
* argv[1]: TracerState
* argv[2]: Tracee
*/
static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifPid to_pid;
if (enif_get_local_pid(env, argv[1], &to_pid))
if (!enif_is_process_alive(env, &to_pid))
if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
/* tracer is dead so we should remove this tracepoint */
return enif_make_atom(env, "remove");
else
return enif_make_atom(env, "discard");
/* Only generate trace for when tracer != tracee */
if (enif_is_identical(argv[1], argv[2]))
return enif_make_atom(env, "discard");
/* Only trigger trace messages on 'send' */
if (enif_is_identical(enif_make_atom(env, "send"), argv[0]))
return enif_make_atom(env, "trace");
/* Have to answer trace_status */
if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
return enif_make_atom(env, "trace");
return enif_make_atom(env, "discard");
}
/*
* argv[0]: TraceTag, should only be 'send'
* argv[1]: TracerState, process to send {Tracee, Recipient} to
* argv[2]: Tracee
* argv[3]: Message
* argv[4]: Options, map containing Recipient
*/
static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifPid to_pid;
ERL_NIF_TERM recipient, msg;
if (enif_get_local_pid(env, argv[1], &to_pid)) {
if (enif_get_map_value(env, argv[4], enif_make_atom(env, "extra"), &recipient)) {
msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], recipient);
enif_send(env, &to_pid, NULL, msg);
}
}
return enif_make_atom(env, "ok");
}
Ericsson AB erts 11.0.2 erl_tracer(3erl)