3.跟踪工具生成器 | 3. Trace Tool Builder

3跟踪工具生成器

3.1引言

跟踪工具生成器是为单节点或分布式Erlang系统构建跟踪工具的基础。它需要运行时[医]工具应用程序可在跟踪节点上使用。

以下是跟踪工具生成器的主要特性:

  • 使用一个函数调用开始跟踪多个节点上的文件端口。

  • 将更多信息写入跟踪信息文件,该文件在格式化期间读取。

  • 通过维护历史缓冲区和处理配置文件来恢复以前的配置。

  • 为顺序跟踪提供一些简单的支持。

  • 格式化多个节点的二进制跟踪日志和合并日志。

Trace Tool Builder的目的是作为量身定制的跟踪工具的基础,但它也可以直接在Erlang shell中使用(它可以模仿dbg行为,同时仍然提供有用的添加,比如匹配规范快捷键)。跟踪工具生成器只允许使用文件端口跟踪器,因此要使用其他类型的跟踪客户端,最好dbg直接使用。

3.2开始

模块ttb是跟踪工具生成器中所有函数的接口。

要开始使用,最少需要做的是启动跟踪器ttb:tracer/0,1,2,并在要跟踪的进程上设置所需的跟踪标志ttb:p/2

跟踪完成后,停止跟踪器ttb:stop/0,1并使用格式化跟踪日志ttb:format/1,2(如果有任何要格式化的)。

有用的功能:

ttb:tracer/0,1,2

在每个要跟踪的节点上打开一个跟踪端口。默认情况下,跟踪消息被写入远程节点上的二进制文件(二进制跟踪日志)。

ttb:p/2

指定要跟踪的进程。此调用中指定的跟踪标志指定要在每个进程上跟踪什么。如果您希望在不同进程上设置不同的跟踪标志,则可以多次调用此函数。

ttb:tp/2,3,4ttb:tpl/2,3,4

如果要跟踪函数调用(即,如果call在任何进程上设置了跟踪标志),则还必须使用ttb:tp/2,3,4或在所需功能上设置跟踪模式ttb:tpl/2,3,4。只有跟踪模式时才会跟踪功能。跟踪模式指定如何使用匹配规范来跟踪功能。匹配规格描述在ERTS User's Guide

ttb:stop/0,1

停止对所有节点的跟踪,删除所有跟踪模式,并刷新跟踪端口缓冲区。

ttb:format/1/2

将二进制跟踪日志翻译成可读的内容。默认情况下,ttb将每条跟踪消息显示为一行文本,但您也可以编写自己的处理程序来对跟踪信息进行更复杂的解释。跟踪日志也可以通过应用程序Event Tracer(ET)以图形方式呈现。

如果format指定了选项ttb:stop/1,则格式化在停止时自动完成ttb

从Erlang Shell跟踪本地节点

在随后的示例中使用了以下小模块:

-module(m). -export([f/0]). f() -> receive From when is_pid(From) -> Now = erlang:now(), From ! {self(),Now} end.

以下示例显示ttb了Erlang shell 的基本用法。默认选项既用于启动跟踪器,也用于格式化(但提供了自定义提取目录)。这给出了Node-ttb在新创建的目录中命名的跟踪日志,其中Node是节点名称。默认处理程序在shell中打印格式化的跟踪消息:

(tiger@durin)47> %% First I spawn a process running my test function (tiger@durin)47> Pid = spawn(m,f,[]). <0.125.0> (tiger@durin)48> (tiger@durin)48> %% Then I start a tracer... (tiger@durin)48> ttb:tracer(). {ok,[tiger@durin]} (tiger@durin)49> (tiger@durin)49> %% and activate the new process for tracing (tiger@durin)49> %% function calls and sent messages. (tiger@durin)49> ttb:p(Pid,[call,send]). {ok,[{<0.125.0>,[{matched,tiger@durin,1}]}]} (tiger@durin)50> (tiger@durin)50> %% Here I set a trace pattern on erlang:now/0 (tiger@durin)50> %% The trace pattern is a simple match spec (tiger@durin)50> %% indicating that the return value should be (tiger@durin)50> %% traced. Refer to the reference_manual for (tiger@durin)50> %% the full list of match spec shortcuts (tiger@durin)50> %% available. (tiger@durin)51> ttb:tp(erlang,now,return). {ok,[{matched,tiger@durin,1},{saved,1}]} (tiger@durin)52> (tiger@durin)52> %% I run my test (i.e. send a message to (tiger@durin)52> %% my new process) (tiger@durin)52> Pid ! self(). <0.72.0> (tiger@durin)53> (tiger@durin)53> %% And then I have to stop ttb in order to flush (tiger@durin)53> %% the trace port buffer (tiger@durin)53> ttb:stop([return, {fetch_dir, "fetch"}]). {stopped, "fetch"} (tiger@durin)54> (tiger@durin)54> %% Finally I format my trace log (tiger@durin)54> ttb:format("fetch"). {<0.125.0>,{m,f,0},tiger@durin}) call erlang:now() {<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 -> {1031,133451,667611} {<0.125.0>,{m,f,0},tiger@durin}) <0.72.0> ! {<0.125.0>,{1031,133451,667611}} ok

建立你自己的工具

以下示例显示了一个简单的“调试跟踪”工具,即使用返回值跟踪函数调用:

-module(mydebug). -export([start/0,trc/1,stop/0,format/1]). -export([print/4]). %% Include ms_transform.hrl so that I can use dbg:fun2ms/2 to %% generate match specifications. -include_lib("stdlib/include/ms_transform.hrl"). %%% -------------Tool API------------- %%% ---------------------------------- %%% Star the "mydebug" tool start() -> %% The options specify that the binary log shall be named %% <Node>-debug_log and that the print/4 function in this %% module shall be used as format handler ttb:tracer(all,[{file,"debug_log"},{handler,{{?MODULE,print},0}}]), %% All processes (existing and new) shall trace function calls %% We want trace messages to be sorted upon format, which requires %% timestamp flag. The flag is however enabled by default in ttb. ttb:p(all,call). %%% Set trace pattern on function(s) trc(M) when is_atom(M) -> trc{M,'_','_'} trc{M,F}) when is_atom(M), is_atom(F) -> trc{M,F,'_'} trc{M,F,_A}=MFA) when is_atom(M), is_atom(F) -> %% This match spec shortcut specifies that return values shall %% be traced. MatchSpec = dbg:fun2ms(fun(_) -> return_trace() end), ttb:tpl(MFA,MatchSpec). %%% Format a binary trace log format(Dir) -> ttb:format(Dir). %%% Stop the "mydebug" tool stop() -> ttb:stop(return). %%% --------Internal functions-------- %%% ---------------------------------- %%% Format handler print(_Out,end_of_trace,_TI,N) -> N; print(Out,Trace,_TI,N) -> do_print(Out,Trace,N), N+1. do_print(Out,{trace_ts,P,call,{M,F,A},Ts},N) -> io:format(Out, "~w: ~w, ~w:~n" "Call : ~w:~w/~w~n" "Arguments :~p~n~n", [N,Ts,P,M,F,length(A),A] do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) -> io:format(Out, "~w: ~w, ~w:~n" "Return from : ~w:~w/~w~n" "Return value :~p~n~n", [N,Ts,P,M,F,A,R]).

为了将使用该工具生成的跟踪日志与其他日志区分开来,可以file使用该选项tracer/2。日志因此被提取到一个名为的目录ttb_upload_debug_log-YYYYMMDD-HHMMSS

通过handler在启动跟踪器时使用选项,关于如何格式化文件的信息存储在跟踪信息文件(.ti)中。这不是必需的,因为它可以在格式化时指定。但是,如果,例如,要使用选项来自动格式化跟踪日志这可能是有用的formatttb:stop/1。此外,您不需要任何二进制日志内容的知识就可以按照预期的方式进行格式化。如果handler在启动跟踪器和格式化时指定了选项,则使用格式化时指定的选项。

跟踪标志call在所有进程上设置。这意味着任何通过命令激活的函数trc/1都可以追踪所有现有的和新的进程。

3.3在远程节点上运行跟踪工具生成器

Observer应用程序可能并不总是可用于要跟踪的节点上(以下称为“跟踪节点”)。但是,只要满足以下条件,Trace Tool Builder仍可以从另一个节点(以下称为“跟踪控制节点”)运行:

  • Observer应用程序在跟踪控制节点上可用。

  • 运行时[医]工具应用程序可在跟踪控制节点和跟踪节点上使用。

如果要对远程节点使用Trace Tool Builder,强烈建议将跟踪控制节点启动为隐藏状态。这样它可以连接到被跟踪的节点而不被它“看到”,也就是说,如果nodes()在跟踪的节点上调用了BIF,则跟踪控制节点不会显示。要启动隐藏节点,请-hidden在该erl命令中添加选项,例如:

% erl -sname trace_control -hidden

无盘节点

如果被跟踪节点是无盘的,则ttb必须从具有磁盘访问权的跟踪控制节点启动,并且file必须指定选项以tracer/2使用值运行{local, File},例如:

(trace_control@durin)1> ttb:tracer(mynode@diskless, {file,{local,{wrap,"mytrace"}}}). {ok,[mynode@diskless]}

3.4多个跟踪选项

设置跟踪时,还可以激活以下功能:

  • 时间约束追踪

  • 过载保护

  • 自动恢复

  • dbg模式

时间约束追踪

在指定的时间段内启用跟踪有时会很有帮助(例如,监视系统24小时或半秒)。这可以通过选项完成{timer, TimerSpec}。如果TimerSpec具有形式MSec,则在MSec使用毫秒后停止跟踪ttb:stop/0。如果提供了更多选项(TimerSpec = {MSec, Opts}),则将ttb:stop/1Opts作为参数调用。

计时器启动时ttb:p/2,必须预先设置任何跟踪图案。ttb:start_trace/4在调用之前总是设置所有模式ttb:p/2

以下示例显示如何设置5秒后自动停止并格式化的跟踪:

(tiger@durin)1> ttb:start_trace([node()], [{erlang, now,[]}], {all, call}, [{timer, {5000, format}}]).

由于网络和处理延迟,跟踪周期是近似的。

过载保护

在跟踪实时系统时,请特别注意不要过重跟踪过载节点。ttb提供overload了解决这个问题的选项。

{overload, MSec, Module, Function}指示ttb后端(Runtime_Tools应用程序的一部分)每MSec毫秒执行一次过载检查。如果检查(named Module:Function(check))返回true,则在所选节点上禁用跟踪。

在一个节点上激活的过载保护不会影响其他节点,其中跟踪按正常方式继续。ttb:stop/0,1从所有客户端获取数据,包括激活过载保护之前收集的所有数据。

一旦在其中一个被跟踪的节点中激活了过载保护,就不允许更改跟踪细节(使用ttb:pttb:tp/tpl...)。这是为了避免节点之间的跟踪设置不一致。

Module:Function提供选项overload必须处理三个电话:initcheck,和stopinitstop允许检查所需的一些设置和拆卸。过载检查模块可以如下所示:

-module(overload). -export([check/1]). check(init) -> Pid = sophisticated_module:start(), put(pid, Pid check(check) -> get(pid) ! is_overloaded, receive Reply -> Reply after 5000 -> true end; check(stop) -> get(pid) ! stop.

check总是被同一个过程调用,所以put并且get是可能的。

自动恢复

一个节点可能会崩溃(可能是一辆越野车,因此被追踪)。用于resume在节点恢复时自动恢复跟踪。发生故障的节点会在Runtime_Tools启动时尝试重新连接到跟踪控制节点。这意味着Runtime_Tools必须包含在其他节点的启动链中(如果没有,您仍然可以通过Runtime_Tools手动启动,即通过RPC调用来恢复跟踪)。

为了不丢失失败节点存储到崩溃点的数据,控制节点会在重新启动跟踪之前尝试获取它。这必须发生在允许的时间范围内,否则会中止(默认为10秒,但可以随时更改{resume, MSec})。以这种方式获取的数据然后与所有其他跟踪合并。

自动启动功能要求更多数据存储在跟踪节点上。默认情况下,数据自动存储在跟踪节点的正确工作目录(cwd)中名为“ttb_autostart.bin”的文件中。用户可以通过指定自己的模块来处理自动启动数据存储和检索(ttb_autostart_module环境变量runtime_tools)来更改此行为(即在无盘节点上)。有关API的信息,请参阅模块ttb。以下示例显示了默认处理程序:

-module(ttb_autostart). -export([read_config/0, write_config/1, delete_config/0]). -define(AUTOSTART_FILENAME, "ttb_autostart.bin"). delete_config() -> file:delete(?AUTOSTART_FILENAME). read_config() -> case file:read_file(?AUTOSTART_FILENAME) of {ok, Data} -> {ok, binary_to_term(Data)}; Error -> Error end. write_config(Data) -> file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).

请记住,文件跟踪端口默认情况下缓冲数据。如果节点崩溃,则跟踪消息不会刷新到二进制日志。如果失败的风险很高,最好自动刷新缓冲区。{flush, MSec}作为一个选项传递ttb:tracer/2MSec毫秒刷新所有缓冲区。

DBG模式

选项{shell, ShellType}允许进行ttb类似的操作dbg{shell, true}在存储它们之前使用在shell中显示所有跟踪消息。{shell, only}另外禁用消息存储(使工具的行为完全一样dbg)。只有IP跟踪端口({trace, {local, File}})才允许这样做。

命令ttb:tracer(dbg)是纯dbg模式({shell, only})的快捷方式。

3.5跟踪信息和File .ti

除了跟踪日志文件外,.ti当Trace Tool Builder启动时,还会创建一个带有扩展名的文件。这是跟踪信息文件。它是一个二进制文件,它包含进程信息,使用的跟踪标志,它所属节点的名称以及用函数写入的所有信息ttb:write_trace_info/2.ti当跟踪停止时,文件总是与其他日志一起提取。

除了过程信息之外,格式化时,跟踪信息文件中的所有内容都将传递到处理函数。参数TI{Key,ValueList}元组列表。该键flagshandlerfile,和node用于直接写入的信息ttb

通过调用可以添加到跟踪信息文件的信息ttb:write_trace_info/2。请注意,这ValueList总是一个列表,如果您write_trace_info/2多次调用相同的内容KeyValueList则每次都会扩展一个新值。

例子:

ttb:write_trace_info(mykey,1)使该条目{mykey,[1]}TI。另一个电话ttb:write_trace_info(mykey,2)将此条目更改为{mykey,[1,2]}

3.6条卷材原木

如果要限制跟踪日志的大小,可以使用换行日志。这工作几乎就像一个循环缓冲区。您可以指定二进制日志的最大数量和每个日志的最大大小。ttb然后每次日志达到最大大小时创建一个新的二进制日志。达到最大日志数时,将在创建新日志之前删除最早的日志。

由生成的数据的总体大小ttb可能比包装规格建议的大。如果跟踪的节点重新启动并且启用了自动恢复功能,则旧的换行日志将始终存储并创建一个新的换行日志。

换行日志可以一个接一个地或一次全部格式化。另看Formatting

3.7格式

格式化可以在停止时自动完成ttb(参见章节Automatically Collect and Format Logs from All Nodes),也可以通过调用函数明确地完成ttb:format/1,2

格式化意味着读取二进制日志并以可读格式显示。您可以使用默认格式处理程序ttb将每个跟踪消息显示为一行文本,或编写自己的处理程序以对跟踪信息进行更复杂的解释。您也可以使用应用程序ET以图形方式显示跟踪日志(请参阅部分Presenting Trace Logs with Event Tracer)。

ttb:format/1,2指定要格式化哪些二进制日志的第一个参数。这通常是ttb在日志提取期间创建的目录的名称。除非disable_sort提供选项,否则不同文件中的日志总是按照跟踪中的时间戳进行排序。

第二个参数ttb:format/2是选项列表,如下所示:

out

指定写入格式化文本的目的地。默认目标是standard_io,但也可以指定文件名。

handler

指定要使用的格式处理程序。如果未指定此选项handler,则使用启动示踪器时指定的选项。如果handler在启动跟踪器时未指定option ,则使用默认处理程序,将每个跟踪消息打印为文本行。

disable_sort

指示日志不会根据时间戳合并,但会一个接一个地处理一个文件(这可能会快一点)。

格式处理程序是一个有四个参数的乐趣。在二进制日志中为每个跟踪消息调用这个乐趣。一个仅打印每条跟踪消息的简单示例可以如下所示:

fun(Fd, Trace, _TraceInfo, State) -> io:format(Fd, "Trace: ~p~n", [Trace]), State end.

这里Fd是目标文件或原子的文件描述符standard_io_TraceInfo包含来自追踪信息文件的信息(参见章节Trace Information and File .ti)。State是格式处理器乐趣的状态变量。变量的初始值由State处理程序选项指定,例如:

ttb:format("tiger@durin-ttb", [{handler, {{Mod,Fun}, initial_state}}]) ^^^^^^^^^^^^^

另一个格式处理程序可用于计算垃圾收集器所花费的时间:

fun(_Fd,{trace_ts,P,gc_start,_Info,StartTs},_TraceInfo,State) -> [{P,StartTs}|State]; (Fd,{trace_ts,P,gc_end,_Info,EndTs},_TraceInfo,State) -> {value,{P,StartTs}} = lists:keysearch(P,1,State), Time = diff(StartTs,EndTs), io:format("GC in process ~w: ~w milliseconds~n", [P,Time]), State -- [{P,StartTs}] end

此格式处理程序的更精细版本是Observer应用程序目录中包含的handle_gc/4模块multitrace.erl中的函数src

跟踪消息作为第二个参数(Trace)传递。可能的值Trace如下:

  • 中描述的所有跟踪消息erlang:trace/3

  • {drop, N}如果使用IP示踪剂(请参阅dbg:trace_port/2

  • end_of_trace 所有跟踪消息都被处理时收到一次

通过提供格式处理程序ttb:get_et_handler(),可以et_viewer在ET应用程序中以图形方式显示跟踪日志(请参阅部分Presenting Trace Logs with Event Tracer)。

您始终可以决定不格式化fetch目录中包含的全部跟踪数据,而是分析单个文件。为此,必须将单个文件(或文件列表)作为第一个参数传递给format/1,2

换行日志可以一个接一个地或一次全部格式化。要格式化其中一个换行日志,请指定确切的文件名。要格式化整套换行日志,请指定名称*而不是换行计数。

例子:

开始追踪:

(tiger@durin)1> ttb:tracer(node(),{file,{wrap,"trace"}}). {ok,[tiger@durin]} (tiger@durin)2> ttb:p(...) ...

这提供了一组二进制日志,例如:

tiger@durin-trace.0.wrp tiger@durin-trace.1.wrp tiger@durin-trace.2.wrp ...

格式化整个日志集:

1> ttb:format("tiger@durin-trace.*.wrp"). .... ok 2>

只格式化第一个日志:

1> ttb:format("tiger@durin-trace.0.wrp"). .... ok 2>

若要合并两个节点的所有包装日志,请执行以下操作:

1> ttb:format(["tiger@durin-trace.*.wrp","lion@durin-trace.*.wrp"]). .... ok 2>

使用事件跟踪器显示跟踪日志

有关事件跟踪器的详细信息,请参阅ET申请。

通过提供格式处理程序ttb:get_et_handler(),可以et_viewer在ET应用程序中以图形方式显示跟踪日志。ttb提供可以从窗口中的菜单Filter中选择的过滤器et_viewer过滤器是根据它们所呈现的参与者的类型(即,序列图中每条垂直线表示的)的名称。演员之间的互动显示为两条垂直线之间的红色箭头,演员内部的活动显示为演员行右侧的蓝色文本。

processes过滤器是从跟踪日志所有跟踪消息的唯一过滤器。序列图中的每条垂直线代表一个过程。Erlang消息,spawn和link/unlink是进程之间的典型交互。函数调用,调度和垃圾收集是流程中的典型活动。processes是默认的过滤器。

其余的过滤器只显示函数调用和函数返回。所有其他跟踪消息都将被丢弃。要充分利用这些过滤器,et_viewer必须知道每个函数的调用者和返回时间。跟踪时可以使用callreturn_to标志来获得。请注意,该标志return_to只适用于本地呼叫追踪,也就是说,追踪模式设置为ttb:tpl

通过call仅使用标志并在本地或全局函数调用上设置匹配规范,可以获得相同的结果,如下所示:

1> dbg:fun2ms(fun(_) -> return_trace(),message(caller()) end). [{'_',[],[{return_trace},{message,{caller}}]}]

然而,这必须谨慎地进行,作为功能。{return_trace}在匹配规范中,销毁尾递归。

modules过滤器显示每个模块作为序列图的垂直线。外部函数调用/返回显示为模块之间的交互,内部函数调用/返回显示为模块内的活动。

functions过滤器示出了每个功能如在序列图的垂直线。调用自身的函数显示为函数内的活动,所有其他函数调用都显示为函数之间的交互。

mods_and_procsfuncs_and_procs过滤器是等同于modulesfunctions分别过滤,除了每个模块或功能可以有许多垂直的线,一个用于每个它驻留在进程。

在下面的示例中,模块foobar使用:

-module(foo). -export([start/0,go/0]). start() -> spawn(?MODULE, go, []). go() -> receive stop -> ok; go -> bar:f1(), go() end.

-module(bar). -export([f1/0,f3/0]). f1() -> f2(), ok. f2() -> spawn(?MODULE,f3,[]). f3() -> ok.

设置跟踪:

(tiger@durin)1> %%First we retrieve the Pid to limit traced processes set (tiger@durin)1> Pid = foo:start(). (tiger@durin)2> %%Now we set up tracing (tiger@durin)2> ttb:tracer(). (tiger@durin)3> ttb:p(Pid, [call, return_to, procs, set_on_spawn]). (tiger@durin)4> ttb:tpl(bar, []). (tiger@durin)5> %%Invoke our test function and see output with et viewer (tiger@durin)5> Pid ! go. (tiger@durin)6> ttb:stop{format, {handler, ttb:get_et_handler()}}).

这将产生类似于以下结果的结果:

图3.1:Filter: "processes"

图3.2:Filter: "mods_and_procs"

注意这个函数ttb:start_trace/4可用作帮助,如下所示:

(tiger@durin)1> Pid = foo:start(). (tiger@durin)2> ttb:start_trace([node()], [{bar,[]}], {Pid, [call, return_to, procs, set_on_spawn]} {handler, ttb:get_et_handler()}). (tiger@durin)3> Pid ! go. (tiger@durin)4> ttb:stop(format).

3.8自动从所有节点收集和格式化日志。

默认情况下,ttb:stop/1从所有节点获取跟踪日志和跟踪信息文件。日志存储在ttb_upload-Filename-Timestamp跟踪控制节点的工作目录下的新目录中。取可以通过提供选项禁用nofetchttb:stop/1。用户可以通过传递选项来指定提取目录{fetch_dir, Dir}

如果format指定了选项ttb:stop/1,跟踪停止后跟踪日志将自动格式化。

3.9历史记录和配置文件

对于跟踪功能,dbg可被用来代替ttb用在过程和迹线图案设置跟踪标志为呼叫跟踪,即,功能ptptplctpctpl,和ctpgttb这些功能只添加以下两件事:

  • 所有调用都存储在历史记录缓冲区中,并可以调用并存储在配置文件中。例如,如果要比较两个测试运行,就可以轻松设置相同的跟踪环境。它还减少了ttb从Erlang shell 使用时的键入量。

  • 为最常见的匹配规范提供了快捷方式(不要强制您dbg:fun2ms持续使用)。

使用ttb:list_history/0查看历史缓冲区的内容,并ttb:run_history/1重新执行中的一个条目。

历史缓冲区的主要目的是创建配置文件的可能性。存储在历史记录缓冲区中的任何函数都可以写入配置文件,并随时用一个函数调用来创建特定配置。

配置文件被创建或扩展ttb:write_config/2,3。配置文件是二进制文件,因此只能使用提供的函数进行读写ttb

历史缓冲区的完整内容可通过调用写入配置文件ttb:write_config(ConfigFile,all)。历史中的选定条目可以通过调用来写入ttb:write_config(ConfigFile,NumList),其中NumList是指出要写入的历史条目的整数列表。而且,历史缓冲区ttb_last_configttb:stop/0,1被调用时总是被转储。

用户定义的条目也可以通过调用函数写入配置文件ttb:write_config(ConfigFile,ConfigList),其中ConfigList列表是{Module,Function,Args}

任何现有文件将ConfigFile被删除,并在write_config/2调用时创建一个新文件。例如,选项append可用于在现有配置文件的末尾添加内容ttb:write_config(ConfigFile,What,[append])

例子:

请参阅历史缓冲区的内容:

(tiger@durin)191> ttb:tracer(). {ok,[tiger@durin]} (tiger@durin)192> ttb:p(self(),[garbage_collection,call]). {ok,{[<0.1244.0>],[garbage_collection,call]}} (tiger@durin)193> ttb:tp(ets,new,2,[]). {ok,[{matched,1}]} (tiger@durin)194> ttb:list_history(). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}]

从历史缓冲区执行一个条目:

(tiger@durin)195> ttb:ctp(ets,new,2). {ok,[{matched,1}]} (tiger@durin)196> ttb:list_history(). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}] (tiger@durin)197> ttb:run_history(3). ttb:tp(ets,new,2,[]) -> {ok,[{matched,1}]}

将历史缓冲区的内容写入配置文件:

(tiger@durin)198> ttb:write_config("myconfig",all). ok (tiger@durin)199> ttb:list_config("myconfig"). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, {5,{ttb,tp,[ets,new,2,[]]}}]

扩展现有配置:

(tiger@durin)200> ttb:write_config("myconfig",[{ttb,tp,[ets,delete,1,[]]}], [append]). ok (tiger@durin)201> ttb:list_config("myconfig"). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, {5,{ttb,tp,[ets,new,2,[]]}}, {6,{ttb,tp,[ets,delete,1,[]]}}]

停止跟踪工具生成器后返回到以前的配置:

(tiger@durin)202> ttb:stop(). ok (tiger@durin)203> ttb:run_config("myconfig"). ttb:tracer(tiger@durin,[]) -> {ok,[tiger@durin]} ttb:p(<0.1244.0>,[garbage_collection,call]) -> {ok,{[<0.1244.0>],[garbage_collection,call]}} ttb:tp(ets,new,2,[]) -> {ok,[{matched,1}]} ttb:ctp(ets,new,2) -> {ok,[{matched,1}]} ttb:tp(ets,new,2,[]) -> {ok,[{matched,1}]} ttb:tp(ets,delete,1,[]) -> {ok,[{matched,1}]} ok

将选定的条目从历史缓冲区写入配置文件:

(tiger@durin)204> ttb:list_history(). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,ctp,[ets,new,2]}}, {5,{ttb,tp,[ets,new,2,[]]}}, {6,{ttb,tp,[ets,delete,1,[]]}}] (tiger@durin)205> ttb:write_config("myconfig",[1,2,3,6]). ok (tiger@durin)206> ttb:list_config("myconfig"). [{1,{ttb,tracer,[tiger@durin,[]]}}, {2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}}, {3,{ttb,tp,[ets,new,2,[]]}}, {4,{ttb,tp,[ets,delete,1,[]]}}] (tiger@durin)207>

3.10序列追踪

要了解什么是顺序跟踪以及如何使用,请参阅参考手册seq_trace

跟踪工具生成器提供的对顺序跟踪的支持包括以下内容:

  • 系统示踪剂的启动。这是在跟踪端口启动时自动完成的ttb:tracer/0,1,2

  • 创建激活顺序跟踪的匹配规范。

启动顺序跟踪需要使用函数启动跟踪程序。ttb:tracer/0,1,2.然后可以通过下列任一种方式开始顺序追踪:

  • 通过使用创建的匹配规范的触发器函数ttb:seq_trigger_ms/0,1

  • 直接使用模块seq_trace

例1:

在下面的示例中,函数dbg:get_tracer/0用作顺序跟踪的触发器:

(tiger@durin)110> ttb:tracer(). {ok,[tiger@durin]} (tiger@durin)111> ttb:p(self(),call). {ok,{[<0.158.0>],[call]}} (tiger@durin)112> ttb:tp(dbg,get_tracer,0,ttb:seq_trigger_ms(send)). {ok,[{matched,1},{saved,1}]} (tiger@durin)113> dbg:get_tracer(), seq_trace:reset_trace(). true (tiger@durin)114> ttb:stop(format). {<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer() SeqTrace [0]: {<0.158.0>,{shell,evaluator,3},tiger@durin}) {<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} [Serial: {0,1}] SeqTrace [0]: {<0.237.0>,dbg,tiger@durin}) {<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.222>}} [Serial: {1,2}] ok (tiger@durin)116>

例2:

如果触发器函数不是直接从shell调用,而是在更大的系统中隐式调用,则使用触发器启动顺序跟踪更有用。当从shell调用函数时,直接开始顺序跟踪比较简单,例如,如下所示:

(tiger@durin)116> ttb:tracer(). {ok,[tiger@durin]} (tiger@durin)117> seq_trace:set_token(send,true), dbg:get_tracer(), seq_trace:reset_trace(). true (tiger@durin)118> ttb:stop(format). SeqTrace [0]: {<0.158.0>,{shell,evaluator,3},tiger@durin}) {<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}} [Serial: {0,1}] SeqTrace [0]: {<0.246.0>,dbg,tiger@durin}) {<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.229>}} [Serial: {1,2}] ok (tiger@durin)120>

在前面的两个例子中,seq_trace:reset_trace/0在跟踪函数之后立即重置跟踪令牌,以避免许多跟踪消息,因为Erlang shell中有打印输出。

模块中的所有功能seq_trace,除了set_system_tracer/1,可以在跟踪端口启动后使用ttb:tracer/0,1,2

3.11多功能跟踪工具

Observer应用程序multitrace目录src中的模块提供了一个包含三种可能跟踪设置的小工具。跟踪消息被写入二进制文件,可以用函数格式化multitrace:format/1,2

multitrace:debug(What)

在所有进程上启动calltrace并跟踪指定的功能。使用的格式处理程序是multitrace:handle_debug/4打印每个呼叫并返回。What必须是一个或多个项目跟踪列表,指定的格式{Module,Function,Arity}{Module,Function}或者只Module

multitrace:gc(Procs)

跟踪指定进程(es)上的垃圾回收。使用的格式处理程序是multitrace:handle_gc/4打印开始,停止以及每个垃圾回收所花费的时间。

multitrace:schedule(Procs)

跟踪指定进程中的调度和调度。所使用的格式处理程序是multitrace:handle_schedule/4用进程,时间戳和当前函数打印每个内部调度和外部调度。它还会打印每个跟踪过程的计划总时间。