檢視原始碼 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
。