erl_tracer
erl_tracer
模块
erl_tracer
模块摘要
Erlang示踪剂行为。
描述
这个行为模块实现了Erlang跟踪系统的后端。只要跟踪探测器被触发,就会调用该模块中的功能。无论是enabled
和trace
函数调用在触发跟踪探测器的实体的范围内。这意味着启用跟踪的开销会受到这些函数花费多少时间的巨大影响。所以,在这些功能上尽可能少做一些工作。
注
此行为中的所有功能都必须作为NIF实施。未来版本中可以删除此限制。example tracer module NIF
本页末尾提供了一个实现。
警告
不要向Tracee
任何回调中发送消息或发出端口命令。这是不允许的,并可能导致各种奇怪的行为,包括但不限于无限递归。
数据类型
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()
使用跟踪器调用的不同跟踪标记。每个跟踪标记详细描述在Module:trace/5
...
tracee() = port() | pid() | undefined
跟踪所属的进程或端口。
trace_opts() =
#{extra => term(),
match_spec_result => term(),
scheduler_id => integer() >= 0,
timestamp =>
timestamp | cpu_timestamp | monotonic | strict_monotonic}
Tracee的选项:
timestamp
如果设置了示踪剂已被请求包括时间戳记。extra
如果设置跟踪点已包含有关跟踪事件的其他数据。附加数据取决于哪一个TraceTag
被触发。所述extra
跟踪数据对应于在所描述的跟踪元组的第五元素erlang:trace/3
。match_spec_result
如果设置了跟踪器,请求包含运行的匹配规范的输出。scheduler_id
如果设置了调度器标识符将被包含在跟踪器中。
tracer_state() = term()
调用时指定的状态erlang:trace(PidPortSpec,true,[{tracer,Module,TracerState}])
。跟踪器状态是传递给erl_tracer
回调函数的不可变值,并且包含生成跟踪事件所需的所有数据。
回调函数
以下函数将从erl_tracer
回调模块导出:
Module:enabled/3
强制性Module:trace/5
强制性Module:enabled_call/3
任选Module:trace_call/5
任选Module:enabled_garbage_collection/3
任选Module:trace_garbage_collection/5
任选Module:enabled_ports/3
任选Module:trace_ports/5
任选Module:enabled_procs/3
任选Module:trace_procs/5
任选Module:enabled_receive/3
任选Module:trace_receive/5
任选Module:enabled_running_ports/3
任选Module:trace_running_ports/5
任选Module:enabled_running_procs/3
任选Module:trace_running_procs/5
任选Module:enabled_send/3
任选Module:trace_send/5
任选
出口
Module:enabled(TraceTag, TracerState, Tracee) -> Result
类型
只要触发了跟踪点,就会调用此回调。它允许跟踪器决定是否生成跟踪。该检查尽可能早,以限制跟踪相关的开销量。如果trace
返回,则创建必要的跟踪数据并调用跟踪器的跟踪回调。如果discard
返回,则此跟踪调用将被丢弃,并且不会调用跟踪。
trace_status
是一种特殊类型TraceTag
,用于检查示踪剂是否仍然有效。它在多种情况下被调用,但最重要的是在使用此跟踪器开始跟踪时使用。如果remove
在trace_status
检查时返回,示踪剂将从Tracee中移除。
该功能可以在每个追踪点多次调用,因此重要的是它既快又无副作用。
Module:enabled_call(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点call | return_to
被触发,就会调用此回调。
如果enabled_call/3
未定义,Module:enabled/3
则调用。
Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点garbage_collection
被触发,就会调用此回调。
如果enabled_garbage_collection/3
未定义,Module:enabled/3
则调用。
Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点ports
被触发,就会调用此回调。
如果enabled_ports/3
未定义,Module:enabled/3
则调用。
Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点procs
被触发,就会调用此回调。
如果enabled_procs/3
未定义,Module:enabled/3
则调用。
Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点'receive'
被触发,就会调用此回调。
如果enabled_receive/3
未定义,Module:enabled/3
则调用。
Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点running_ports
被触发,就会调用此回调。
如果enabled_running_ports/3
未定义,Module:enabled/3
则调用。
Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result
类型
只要带有跟踪标志的跟踪点running_procs | running
被触发,就会调用此回调。
如果enabled_running_procs/3
未定义,Module:enabled/3
则调用。
Module:enabled_send(TraceTag, TracerState, Tracee) -> Result
类型
每当有跟踪标志的跟踪点时,都会调用此回调。send
被触发了。
如果enabled_send/3
是未知的,Module:enabled/3
而是被称为。
Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled/3
回调返回trace
在它中,示踪剂所需的任何副作用都要做。跟踪点有效载荷位于TraceTerm
.“公约”的内容TraceTerm
取决于TraceTag
被触发了。TraceTerm
中描述的跟踪元组中的第四个元素。erlang:trace/3
...
如果跟踪元组有五个元素,则第五个元素将作为extra
值中的Opts
地图。
Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) -> Result
类型
大TraceTag
seq_trace
处理方式略有不同。没有Tracee
为seq_trace
,而不是Label
与seq_trace
事件。
有关什么的更多信息Label
和SeqTraceInfo
可以,看seq_trace(3)
...
Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_call/3
回调返回trace
...
如果trace_call/5
是未知的,Module:trace/5
而是被称为。
Module:trace_garbage_collection(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_garbage_collection/3
回调返回trace
...
如果trace_garbage_collection/5
是未知的,Module:trace/5
而是被称为。
Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_ports/3
回调返回trace
...
如果trace_ports/5
是未知的,Module:trace/5
而是被称为。
Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_procs/3
回调返回trace
...
如果trace_procs/5
是未知的,Module:trace/5
而是被称为。
Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_receive/3
回调返回trace
...
如果trace_receive/5
是未知的,Module:trace/5
而是被称为。
Module:trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_running_ports/3
回调返回trace
...
如果trace_running_ports/5
是未知的,Module:trace/5
而是被称为。
Module:trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_running_procs/3
回调返回trace
...
如果trace_running_procs/5
是未知的,Module:trace/5
而是被称为。
Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result
类型
当触发跟踪点时,当Module:enabled_send/3
回调返回trace
...
如果trace_send/5
是未知的,Module:trace/5
而是被称为。
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"
}