查看源代码 erl_tracer 行为 (erts v15.2)

Erlang 跟踪器行为。

此行为模块实现了 Erlang 跟踪系统的后端。每当触发跟踪探针时,都会调用此模块中的函数。 enabledtrace 函数都在触发跟踪探针的实体的上下文中调用。这意味着启用跟踪的开销很大程度上受到这些函数中花费的时间的影响。因此,在这些函数中尽可能少地执行操作。

注意

此行为中的所有函数都必须实现为 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 时,会调用此回调。

类型

链接到此类型

trace_opts()

查看源代码 (自 OTP 19.0 起)
-type trace_opts() ::
          #{extra => term(),
            match_spec_result => term(),
            scheduler_id => non_neg_integer(),
            timestamp => timestamp | cpu_timestamp | monotonic | strict_monotonic}.

跟踪对象的选项

  • timestamp - 如果设置,则请求跟踪器包括时间戳。

  • extra - 如果设置,则跟踪点已包括有关跟踪事件的其他数据。其他数据是什么取决于触发了哪个 TraceTagextra 跟踪数据对应于 trace:process/4 中描述的跟踪元组中的第五个元素。

  • match_spec_result - 如果设置,则请求跟踪器包括运行的匹配规范的输出。

  • scheduler_id - 如果设置,则调度程序 ID 将包含在跟踪器中。

链接到此类型

trace_tag()

查看源代码 (自 OTP 19.0 起)

调用跟踪器的不同跟踪标签。

每个跟踪标签都在 Module:trace/5 中详细描述。

链接到此类型

trace_tag_call()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_call() :: call | return_to | return_from | exception_from.
链接到此类型

trace_tag_gc()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_gc() :: gc_minor_start | gc_minor_end | gc_major_start | gc_major_end.
链接到此类型

trace_tag_ports()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_ports() :: open | closed | link | unlink | getting_linked | getting_unlinked.
链接到此类型

trace_tag_procs()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_procs() ::
          spawn | spawned | exit | link | unlink | getting_linked | getting_unlinked | register |
          unregister.
链接到此类型

trace_tag_receive()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_receive() :: 'receive'.
链接到此类型

trace_tag_running_ports()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_running_ports() :: in | out | in_exiting | out_exiting | out_exited.
链接到此类型

trace_tag_running_procs()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_running_procs() :: in | out | in_exiting | out_exiting | out_exited.
链接到此类型

trace_tag_send()

查看源代码 (自 OTP 19.0 起)
-type trace_tag_send() :: send | send_to_non_existing_process.
链接到此类型

tracee()

查看源代码 (自 OTP 19.0 起)
-type tracee() :: port() | pid() | undefined.

跟踪所属的进程或端口。

回调

链接到此回调

enabled(TraceTag, TracerState, Tracee)

查看源代码 (自 OTP 19.0 起)
-callback enabled(TraceTag, TracerState, Tracee) -> Result
                     when
                         TraceTag :: trace_tag() | trace_status,
                         TracerState :: term(),
                         Tracee :: tracee(),
                         Result :: trace | discard | remove.

每当触发跟踪点时,都会调用此回调。

它允许跟踪器决定是否要生成跟踪。此检查会尽早进行,以限制与跟踪相关的开销。如果返回 trace,则会创建必要的跟踪数据,并调用跟踪器的跟踪回调。如果返回 discard,则会丢弃此跟踪调用,并且不执行任何跟踪调用。

trace_statusTraceTag 的一种特殊类型,用于检查跟踪器是否仍处于活动状态。它在多种情况下被调用,但最重要的是在使用此跟踪器启动跟踪时使用。如果在检查 trace_status 时返回 remove,则会从跟踪对象中删除跟踪器。

此函数可以在每个跟踪点多次调用,因此重要的是它既要快速又没有副作用。

链接到此回调

enabled_call(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_garbage_collection(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_ports(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_procs(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_receive(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_running_ports(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

enabled_running_procs(TraceTag, TracerState, Tracee)

查看源代码 (自 OTP 19.0 起)
-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

链接到此回调

enabled_send(TraceTag, TracerState, Tracee)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

trace(Tag, TracerState, Tracee, Msg, Opts)

查看源代码 (自 OTP 19.0 起)
-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 的内容取决于触发的 TraceTagTraceTerm 对应于 trace:process/4 中描述的跟踪元组中的第四个元素。

如果跟踪元组有五个元素,则第五个元素将作为 Opts 映射中的 extra 值发送。

TraceTag seq_trace 的处理方式略有不同。seq_trace 没有 Tracee,而是指定与 seq_trace 事件关联的 Label

有关 LabelSeqTraceInfo 可以是什么的更多信息,请参阅 seq_trace

链接到此回调

trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (可选) (自 OTP 19.0 起)
-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

链接到此回调

trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (自 OTP 19.0 起)
-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

链接到此回调

trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts)

查看源代码 (可选) (自 OTP 19.0 起)
-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