查看源代码 erl_tracer 行为 (erts v15.2)
Erlang 跟踪器行为。
此行为模块实现了 Erlang 跟踪系统的后端。每当触发跟踪探针时,都会调用此模块中的函数。 enabled
和 trace
函数都在触发跟踪探针的实体的上下文中调用。这意味着启用跟踪的开销很大程度上受到这些函数中花费的时间的影响。因此,在这些函数中尽可能少地执行操作。
注意
此行为中的所有函数都必须实现为 NIF。此限制可以在将来的版本中删除。下面提供了 示例跟踪器模块 NIF 实现。
警告
请勿在任何回调中向
Tracee
发送消息或发出端口命令。这是不允许的,并且会导致各种奇怪的行为,包括但不限于无限递归。
Erl 跟踪器模块示例
在此示例中,具有 NIF 后端的跟踪器模块为每个包含发送者和接收者的 send
跟踪标签发送一条消息。使用此跟踪器模块,可以使用更轻量级的消息跟踪器,该跟踪器仅记录谁向谁发送消息。
以下是在 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");
}
总结
回调
每当触发跟踪点时,都会调用此回调。
每当触发带有跟踪标志 call | return_to
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 garbage_collection
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 ports
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 procs
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 'receive'
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 running_ports
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 running_procs | running
的跟踪点时,都会调用此回调。
每当触发带有跟踪标志 send
的跟踪点时,都会调用此回调。
当触发跟踪点并且 Module:enabled/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_call/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_garbage_collection/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_ports/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_procs/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_receive/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_running_ports/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_running_procs/3
回调返回 trace
时,会调用此回调。
当触发跟踪点并且 Module:enabled_send/3
回调返回 trace
时,会调用此回调。
类型
-type trace_opts() :: #{extra => term(), match_spec_result => term(), scheduler_id => non_neg_integer(), timestamp => timestamp | cpu_timestamp | monotonic | strict_monotonic}.
跟踪对象的选项
timestamp
- 如果设置,则请求跟踪器包括时间戳。extra
- 如果设置,则跟踪点已包括有关跟踪事件的其他数据。其他数据是什么取决于触发了哪个TraceTag
。extra
跟踪数据对应于 trace:process/4 中描述的跟踪元组中的第五个元素。match_spec_result
- 如果设置,则请求跟踪器包括运行的匹配规范的输出。scheduler_id
- 如果设置,则调度程序 ID 将包含在跟踪器中。
-type 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().
调用跟踪器的不同跟踪标签。
每个跟踪标签都在 Module:trace/5
中详细描述。
-type trace_tag_call() :: call | return_to | return_from | exception_from.
-type trace_tag_gc() :: gc_minor_start | gc_minor_end | gc_major_start | gc_major_end.
-type trace_tag_ports() :: open | closed | link | unlink | getting_linked | getting_unlinked.
-type trace_tag_procs() ::
spawn | spawned | exit | link | unlink | getting_linked | getting_unlinked | register |
unregister.
-type trace_tag_receive() :: 'receive'.
-type trace_tag_running_ports() :: in | out | in_exiting | out_exiting | out_exited.
-type trace_tag_running_procs() :: in | out | in_exiting | out_exiting | out_exited.
-type trace_tag_send() :: send | send_to_non_existing_process.
跟踪所属的进程或端口。
回调
-callback enabled(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag() | trace_status, TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发跟踪点时,都会调用此回调。
它允许跟踪器决定是否要生成跟踪。此检查会尽早进行,以限制与跟踪相关的开销。如果返回 trace
,则会创建必要的跟踪数据,并调用跟踪器的跟踪回调。如果返回 discard
,则会丢弃此跟踪调用,并且不执行任何跟踪调用。
trace_status
是 TraceTag
的一种特殊类型,用于检查跟踪器是否仍处于活动状态。它在多种情况下被调用,但最重要的是在使用此跟踪器启动跟踪时使用。如果在检查 trace_status
时返回 remove
,则会从跟踪对象中删除跟踪器。
此函数可以在每个跟踪点多次调用,因此重要的是它既要快速又没有副作用。
-callback enabled_call(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_call(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 call | return_to
的跟踪点时,都会调用此回调。
如果未定义 enabled_call/3
,则改为调用 Module:enabled/3
。
-callback enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_gc(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 garbage_collection
的跟踪点时,都会调用此回调。
如果未定义 enabled_garbage_collection/3
,则改为调用 Module:enabled/3
。
-callback enabled_ports(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_ports(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 ports
的跟踪点时,都会调用此回调。
如果 enabled_ports/3
未定义,则会改为调用 Module:enabled/3
。
-callback enabled_procs(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_procs(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 procs
的跟踪点时,都会调用此回调。
如果 enabled_procs/3
未定义,则会改为调用 Module:enabled/3
。
-callback enabled_receive(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_receive(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 'receive'
的跟踪点时,都会调用此回调。
如果 enabled_receive/3
未定义,则会改为调用 Module:enabled/3
。
-callback enabled_running_ports(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_running_ports(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 running_ports
的跟踪点时,都会调用此回调。
如果 enabled_running_ports/3
未定义,则会改为调用 Module:enabled/3
。
-callback enabled_running_procs(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_running_procs(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 running_procs | running
的跟踪点时,都会调用此回调。
如果 enabled_running_procs/3
未定义,则会改为调用 Module:enabled/3
。
-callback enabled_send(TraceTag, TracerState, Tracee) -> Result when TraceTag :: trace_tag_send(), TracerState :: term(), Tracee :: tracee(), Result :: trace | discard | remove.
每当触发带有跟踪标志 send
的跟踪点时,都会调用此回调。
如果 enabled_send/3
未定义,则会改为调用 Module:enabled/3
。
-callback trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) -> Result when TracerState :: term(), Label :: term(), SeqTraceInfo :: term(), Opts :: trace_opts(), Result :: ok; (TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled/3
回调返回 trace
时,会调用此回调。
跟踪器所需的任何副作用都应在此处完成。跟踪点有效负载位于 TraceTerm
中。TraceTerm
的内容取决于触发的 TraceTag
。TraceTerm
对应于 trace:process/4
中描述的跟踪元组中的第四个元素。
如果跟踪元组有五个元素,则第五个元素将作为 Opts
映射中的 extra
值发送。
TraceTag
seq_trace
的处理方式略有不同。seq_trace
没有 Tracee
,而是指定与 seq_trace
事件关联的 Label
。
有关 Label
和 SeqTraceInfo
可以是什么的更多信息,请参阅 seq_trace
。
-callback trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_call(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_call/3
回调返回 trace
时,会调用此回调。
如果 trace_call/5
未定义,则会改为调用 Module:trace/5
。
trace_garbage_collection(TraceTag, TracerState, Tracee, TraceTerm, Opts)
查看源代码 (可选) (自 OTP 19.0 起)-callback trace_garbage_collection(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_gc(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_garbage_collection/3
回调返回 trace
时,会调用此回调。
如果 trace_garbage_collection/5
未定义,则会改为调用 Module:trace/5
。
-callback trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_ports/3
回调返回 trace
时,会调用此回调。
如果 trace_ports/5
未定义,则会改为调用 Module:trace/5
。
-callback trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_procs/3
回调返回 trace
时,会调用此回调。
如果 trace_procs/5
未定义,则会改为调用 Module:trace/5
。
-callback trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_receive(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_receive/3
回调返回 trace
时,会调用此回调。
如果 trace_receive/5
未定义,则会改为调用 Module:trace/5
。
trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts)
查看源代码 (可选) (自 OTP 19.0 起)-callback trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_running_ports(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_running_ports/3
回调返回 trace
时,会调用此回调。
如果 trace_running_ports/5
未定义,则会改为调用 Module:trace/5
。
-callback trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_running_procs(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_running_procs/3
回调返回 trace
时,会调用此回调。
如果 trace_running_procs/5
未定义,则会改为调用 Module:trace/5
。
-callback trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result when TraceTag :: trace_tag_send(), TracerState :: term(), Tracee :: tracee(), TraceTerm :: term(), Opts :: trace_opts(), Result :: ok.
当触发跟踪点并且 Module:enabled_send/3
回调返回 trace
时,会调用此回调。
如果 trace_send/5
未定义,则会改为调用 Module:trace/5
。