非常教程

Erlang 20参考手册

ERTS/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");
}

ERTS/erl_tracer相关

Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1