This behavior module implements the back end of the Erlang
tracing system. The functions in this module are called whenever
a trace probe is triggered. Both the
All functions in this behavior must be implemented as NIFs.
This limitation can be removed in a future releases.
An
Do not send messages or issue port commands to the
The different trace tags that the tracer is called with.
Each trace tag is described in detail in
The process or port that the trace belongs to.
The options for the tracee:
The state specified when calling
The following functions are to be exported from an
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
This function can be called multiple times per tracepoint, so it is important that it is both fast and without side effects.
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called whenever a tracepoint with trace flag
If
This callback is called when a tracepoint is triggered and the
If the trace tuple has five elements, the fifth element
will be sent as the
The
For more information on what
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
This callback is called when a tracepoint is triggered and the
If
In this example, a tracer module with a NIF back end sends a
message for each
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>
-module(erl_msg_tracer). -export([enabled/3, trace/5, load/0]). load() -> erlang:load_nif("erl_msg_tracer", []). enabled(_, _, _) -> error. trace(_, _, _, _, _) -> error.
#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"); }