erl_tracer

erl_tracer

模块

erl_tracer

模块摘要

Erlang示踪剂行为。

描述

这个行为模块实现了Erlang跟踪系统的后端。只要跟踪探测器被触发,就会调用该模块中的功能。无论是enabledtrace函数调用在触发跟踪探测器的实体的范围内。这意味着启用跟踪的开销会受到这些函数花费多少时间的巨大影响。所以,在这些功能上尽可能少做一些工作。

此行为中的所有功能都必须作为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/3match_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,用于检查示踪剂是否仍然有效。它在多种情况下被调用,但最重要的是在使用此跟踪器开始跟踪时使用。如果removetrace_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

类型

TraceTagseq_trace处理方式略有不同。没有Traceeseq_trace,而不是Labelseq_trace事件。

有关什么的更多信息LabelSeqTraceInfo可以,看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" }