dbg
DBG
模块
DBG
模块摘要
基于文本的跟踪工具
描述
此模块实现了一个基于文本的接口,该接口用于trace/3和trace_pattern/2
BIF。它使跟踪函数、进程、端口和消息成为可能。
要快速开始跟踪函数调用,可以在Erlangshell中使用以下代码:
1> dbg:tracer(). %% Start the default trace message receiver
{ok,<0.36.0>}
2> dbg:p(all, c). %% Setup call (c) tracing on all processes
{ok,[{matched,nonode@nohost,26}]}
3> dbg:tp(lists, seq, x). %% Setup an exception return trace (x) on lists:seq
{ok,[{matched,nonode@nohost,2},{saved,x}]}
4> lists:seq(1,10).
(<0.34.0>) call lists:seq(1,10)
(<0.34.0>) returned from lists:seq/2 -> [1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
有关如何使用dbg
在Erlang shell中,请参阅simple example
部分。
这些实用工具也适用于大型系统上的系统测试,因为其他工具对系统性能影响太大。还包括了对顺序跟踪的一些基本支持,请参阅advanced topics
部分。
导出
fun2ms(LiteralFun) -> MatchSpec
类型
伪函数通过的手段parse_transform
平移字面
fun()
作为中所述类型化如在函数调用的匹配规格参数match_spec
ERTS用户指南的手册。(我的意思是,fun()
需要将文本写为函数的参数,它不能保存在一个变量中,该变量又传递给函数)。
解析转换在模块中实现,ms_transform
并且源必须
ms_transform.hrl
在STDLIB中包含该伪文件中的文件才能工作。无法在源文件中包含hrl文件将导致运行时错误,而不是编译时间同上。通过将该行添加-include_lib("stdlib/include/ms_transform.hrl").
到源文件中,包含文件是最简单的。
这fun()
是非常有限的,它可以只需要一个参数(参数列表匹配),唯一的变量或列表。它需要使用is_
XXX后卫测试和一个不能使用不具有代表性的match_spec(如语言结构if
,case
,receive
等)。fun的返回值将是结果match_spec的返回值。
例子:
1> dbg:fun2ms(fun([M,N]) when N > 3 -> return_trace() end).
[{['$1','$2'],[{'>','$2',3}],[{return_trace}]}]
可以从环境中导入变量,这样可以实现:
2> X=3.
3
3> dbg:fun2ms(fun([M,N]) when N > X -> return_trace() end).
[{['$1','$2'],[{'>','$2',{const,3}}],[{return_trace}]}]
导入的变量将被匹配替换。[医]规格const
表达式,这与Erlang的静态作用域一致。fun()
但是,局部或全局函数调用不可能是乐趣的守卫或身体。调用内置匹配[医]当然,规范功能是允许的:
4> dbg:fun2ms(fun([M,N]) when N > X, is_atomm(M) -> return_trace() end).
Error: fun containing local erlang function calls ('is_atomm' called in guard)\
cannot be translated into match_spec
{error,transform_error}
5> dbg:fun2ms(fun([M,N]) when N > X, is_atom(M) -> return_trace() end).
[{['$1','$2'],[{'>','$2',{const,3}},{is_atom,'$1'}],[{return_trace}]}]
正如您在示例中所看到的,该函数也可以从shell中调用。fun()
从shell中使用时,需要从字面上理解。除了parse_transform之外的其他方法在shell中使用,但是应用或多或少相同的限制(例外是记录,因为它们不由shell处理)。
警告
如果parse_transform
未应用于调用此伪函数的模块,则调用将在运行时(使用一个 badarg
)失败。该模块dbg
实际上用这个名称导出了一个函数,但除了在shell中使用该函数之外,它应该永远不会被调用。如果parse_transform
通过包含ms_transform.hrl
头文件正确应用,则编译后的代码将永远不会调用该函数,但该函数调用将由文字match_spec替代。
更多信息由ms_transform
STDLIB中的手册页。
h() -> ok
给出了一个项目的列表,以便提供简短的在线帮助。
h(Item) -> ok
类型
为DBG模块中的函数提供一个简短的帮助文本。可用的项目可以用dbg:h/0
p(Item) -> {ok, MatchDesc} | {error, term()}
相当于p(Item, [m])
。
p(Item, Flags) -> {ok, MatchDesc} | {error, term()}
类型
痕迹Item
按照Flags
...的变化Item
列于下:
pid() 或者 port()跟踪相应的进程或端口。进程或端口可能是远程进程或端口(在另一个Erlang节点上)。该节点必须位于被跟踪节点的列表中(请参阅n/1和tracer/3)。all系统中的所有进程和端口以及此后创建的所有进程和端口都将被跟踪。processes系统中的所有过程以及此后创建的所有过程都将被跟踪。ports系统中的所有端口以及此后创建的所有端口都将被跟踪。new呼叫后创建的所有进程和端口都将被跟踪。new_processes呼叫后创建的所有进程都要跟踪。new_ports通话后创建的所有端口都将被跟踪。existing跟踪所有现有的进程和端口。existing_processes追踪所有现有流程。existing_ports所有现有的端口都被追踪。atom()跟踪具有相应注册名称的进程或端口。进程或端口可能是一个远程进程(在另一个Erlang节点上)。该节点必须添加n/1或tracer/3功能。追踪integer()过程<0.Item.0>。追踪{X, Y, Z}过程<X.Y.Z>。 string()如果返回的Item是字符串“<XYZ>” pid_to_list/1,<X.Y.Z>则跟踪该过程。
当启用Item
表示一组进程的Item
对象添加的所有节点上都启用了n/1
或tracer/3
功能。
Flags
可以是单个原子,也可以是标志列表。可用的标志是:
s (send)
跟踪进程或端口发送的消息。
r (receive)
跟踪进程或端口接收的消息。
m (messages)
跟踪进程或端口接收和发送的消息。
c (call)
根据系统中设置的跟踪模式跟踪进程的全局函数调用(请参阅tp / 2)。
p (procs)
跟踪与进程相关的事件。
ports
将与端口相关的事件跟踪到端口。
sos (set on spawn)
允许由跟踪进程创建的所有进程继承跟踪进程的跟踪标志。
sol (set on link)
让另一个进程P2
在被跟踪进程链接时继承跟踪进程的跟踪标志P2
。
sofs (set on first spawn)
这和sos
,但只适用于跟踪过程产生的第一个过程。
sofl (set on first link)
这和sol
,但只适用于第一个呼叫link/1
通过追踪过程。
all
设置除silent
...
clear
清除所有标志。
列表还可以包括允许的任何标志。erlang:trace/3
该函数返回一个错误元组或元组{ok, List}
。在List
由多少进程和端口的规格相匹配(在纯PID()正好1的情况)。匹配过程的规格是{matched, Node, N}
。如果远程处理器rpc
对远程节点调用失败,则rpc
错误消息作为第四个参数传递,并且匹配进程的数量为0.请注意,结果{ok,List
}可能包含rpc
调用一个,几个甚至所有节点都失败了。
c(Mod, Fun, Args)
相当于c(Mod, Fun, Args, all)
...
c(Mod, Fun, Args, Flags)
计算表达式apply(Mod, Fun, Args)
中有跟踪标志Flags
准备好了。这是从Erlang shell跟踪进程的一种方便方法。
i() -> ok
显示有关所有跟踪进程和端口的信息。
tp(Module,MatchSpec)
与tp相同({Module,'_','_'},MatchSpec)
tp(Module,Function,MatchSpec)
与tp相同({Module,Function,'_'},MatchSpec)
tp(Module, Function, Arity, MatchSpec)
与tp相同({Module,Function,Arity},MatchSpec)
tp{Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}
类型
此函数为一个或多个函数启用调用跟踪。所有导出的函数都匹配{Module, Function, Arity}
争论会引起关注,但是match_spec()
可能会进一步缩小生成跟踪消息的函数调用集。
有关match_spec()
语法的说明,请参阅运行系统(erts
)的在线文档的用户指南
部分。本章解释了一般匹配规范“语言”。使用的最常见的通用匹配规范可以找到',详见下文。Match Specifications in ErlangBuilt-inAliasltp/0
The Module, Function and/or Arity parts of the tuple may be specified as the atom '_'
which is a "wild-card" matching all modules/functions/arities. Note, if the Module is specified as '_'
, the Function and Arity parts have to be specified as '_'
too. The same holds for the Functions relation to the Arity.
添加了所有节点n/1
或tracer/3
将受到此调用的影响,如果模块不受此影响'_'
模块将加载到所有节点上。
该函数返回一个错误元组或元组{ok, List}
。它List
包含多少个匹配函数的规范,与进程和端口的返回值一样p/2
。
可能有一个元组{saved, N}
在返回值中,如果MatchSpec不是。[].整数N
然后可以在以后调用此函数时使用,并充当给定表达式的“别名”。还有几个内置的别名用于常见表达式,请参见ltp/0
下面是详细信息。
如果返回错误,则可能是由于在编译匹配规范时出现错误。这些错误以元组列表的形式表示。{error, string()}
其中字符串是编译错误的文本解释。例如:
(x@y)4> dbg:tp{dbg,ltp,0},[{[],[],[{message, two, arguments}, {noexist}]}]).
{error,
[{error,"Special form 'message' called with wrong number of
arguments in {message,two,arguments}."},
{error,"Function noexist/1 does_not_exist."}]}
tpl(Module,MatchSpec)
与tpl相同({Module,'_','_'},MatchSpec)
tpl(Module,Function,MatchSpec)
与tpl相同({模块,函数,'_'},MatchSpec)
tpl(Module, Function, Arity, MatchSpec)
与tpl({Module,Function,Arity},MatchSpec)相同
tpl{Module, Function, Arity}, MatchSpec) -> {ok, MatchDesc} | {error, term()}
这个函数的作用是tp/2
,但能够跟踪本地调用(和本地函数)以及全局调用(和函数)。
tpe(Event, MatchSpec) -> {ok, MatchDesc} | {error, term()}
类型
此函数将匹配规范与跟踪事件关联起来。send
或'receive'
默认情况下,所有已执行send
和'receive'
如果为进程启用了事件,则跟踪事件。匹配规范可用于基于发送方、接收方和/或消息内容过滤跟踪事件。
有关match_spec()
语法的说明,请参阅运行系统(erts
)的在线文档的用户指南
部分。本章解释了一般匹配规范“语言”。Match Specifications in Erlang
因为send
,匹配是在列表上完成的[Receiver, Msg]
。Receiver
是接收方的进程或端口标识,Msg
是消息术语。发送过程的pid可以通过保护功能访问self/0
。
因为'receive'
,匹配是在列表上完成的[Node, Sender, Msg]
。Node
是发件人的节点名称。Sender
是发件人的进程或端口标识,或者是undefined
发件人未知的原子(远程发件人可能是这种情况)。Msg
是消息术语。接收过程的pid可以通过保护功能进行访问self/0
。
添加了所有节点n/1
或tracer/3
会受到这个电话的影响。
返回值与for相同tp/2
。匹配事件的数量从不大于1,因为tpe/2
不接受任何形式的参数通配符Event
。
ctp()
与ctp相同({'_','_','_'})
ctp(Module)
与ctp相同({Module,'_','_'})
ctp(Module, Function)
与ctp相同({Module,Function,'_'})
ctp(Module, Function, Arity)
与ctp相同({Module,Function,Arity})
ctp{Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}
类型
此功能禁用指定功能的呼叫跟踪。参数的语义与tp/2
中相应的函数说明相同tpl/2
。本地和全局呼叫跟踪都被禁用。
返回值反映了匹配的多少个函数,并按照其中的描述构建tp/2
。{saved, N}
然而,不会返回元组(因为显而易见的原因)。
ctpl()
与ctpl相同({'_','_','_'})
ctpl(Module)
与ctpl相同({Module,'_','_'})
ctpl(Module, Function)
与ctpl相同({Module,Function,'_'})
ctpl(Module, Function, Arity)
与ctpl相同({Module,Function,Arity})
ctpl{Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}
这个函数的作用是ctp/1
,但只禁止跟踪tpl/2
(不与tp/2
)。
ctpg()
与ctpg相同({'_','_','_'})
ctpg(Module)
与ctpg相同({Module,'_','_'})
ctpg(Module, Function)
与ctpg相同({Module,Function,'_'})
ctpg(Module, Function, Arity)
与ctpg相同({Module,Function,Arity})
ctpg{Module, Function, Arity}) -> {ok, MatchDesc} | {error, term()}
这个函数的作用是ctp/1
,但只禁止跟踪tp/2
(不与tpl/2
)。
ctpe(Event) -> {ok, MatchDesc} | {error, term()}
类型
此函数清除指定跟踪事件(send
或'receive'
)的匹配规范。它将恢复为跟踪所有触发事件的默认行为。
返回值与样式相同ctp/1
。
ltp() -> ok
使用此函数可以调用以前在会话中使用的所有匹配规范(即先前在调用过程中保存的内容tp/2
以及内置的匹配规范,这非常有用,因为复杂的match_spec在编写时会非常尴尬。如果stop/0
被调用则丢失。
所使用的匹配规范可以保存在一个文件中(如果存在读写文件系统),以便在稍后的调试会话中使用,请参阅wtp/1
和rtp/1
有三个内置线圈图案:exception_trace
,caller_trace
和caller_exception_trace
(或x
,c
和cx
分别)。异常跟踪设置一个跟踪,它将显示函数名称,参数,返回值和从函数抛出的异常。调用者跟踪显示函数名称,参数和有关哪个函数调用它的信息。使用内置别名的示例:
(x@y)4> dbg:tp(lists,sort,cx).
{ok,[{matched,nonode@nohost,2},{saved,cx}]}
(x@y)4> lists:sort([2,1]).
(<0.32.0>) call lists:sort([2,1]) {erl_eval,do_apply,5})
(<0.32.0>) returned from lists:sort/1 -> [1,2]
[1,2]
dtp() -> ok
使用此函数“忘记”在调用tp/2
当您想要从以下文件中恢复其他匹配规范时,这是非常有用的。rtp/1
.使用dtp/1
若要删除特定保存的匹配规范,请执行以下操作。
dtp(N) -> ok
类型
使用此功能“忘记”在呼叫期间保存的特定匹配规格tp/2
。
wtp(Name) -> ok | {error, IOError}
类型
此功能将保存在会话期间(在呼叫期间tp/2
)保存的所有匹配规格,以及以指定名称的文本文件保存内置匹配规格Name
。文件的格式是文本格式,为什么可以用普通的文本编辑器编辑,然后使用恢复rtp/1
。
文件中的每个匹配规范以句号(.
)和新的(语法正确)匹配规范结尾,可以手动添加到文件中。
函数返回ok
或者一个错误元组,其中第二个元素包含I/O错误,这使得编写不可能。
rtp(Name) -> ok | {error, Error}
类型
此函数从由wtp/1
功能。它检查所有匹配规范的语法并验证它们是否正确。错误处理原则是“全部或无”,即如果某些匹配规范是错误的,则没有一个规范被添加到运行系统保存的匹配规范列表中。
文件中的匹配规范如下合并
使用当前匹配规范,这样就不会生成重复项。使用ltp/0
查看从文件中分配给规范的数字。
由于I / O问题(如不存在或不可读的文件)或由于文件格式问题,该函数将返回错误。来自不良格式文件的错误或多或少具有文本格式,这会提示导致问题的原因。
n(Nodename) -> {ok, Nodename} | {error, Reason}
类型
该dbg
服务器将应该在哪里进行跟踪节点列表。无论何时进行tp/2
呼叫或p/2
呼叫,它都会针对该列表中的所有节点(包括本地节点)执行(除了p/2
具有特定pid()
或port()
第一个参数外,在这种情况下,该命令仅在指定进程或端口的节点上执行所在)。
该功能将远程节点(Nodename
)添加到执行跟踪的节点列表中。它在远程节点上启动一个跟踪进程,它将把所有跟踪消息发送到本地节点上的跟踪进程(通过Erlang分发)。如果本地节点上没有运行跟踪器进程,no_local_tracer
则返回错误原因。本地节点上的跟踪器进程必须使用该tracer/0/2
函数启动。
如果Nodename
是本地节点的错误原因。cant_add_local_node
会被归还。
如果跟踪端口(请参阅trace_port/2
)正在本地节点上运行,则无法使用跟踪器进程跟踪远程节点。错误原因cant_trace_remote_pid_to_local_port
返回。跟踪端口可以通过该tracer/3
功能在远程节点上启动。
如果节点Nodename
不可达,该函数也会返回一个错误。
cn(Nodename) -> ok
类型
从跟踪节点列表中清除节点。后续调用tp/2
并p/2
不会考虑该节点,但已在节点上激活的跟踪将继续生效。
返回ok
,不能失败。
ln() -> ok
显示控制台上跟踪节点的列表。
tracer() -> {ok, pid()} | {error, already_started}
该功能在本地节点上启动服务器,该节点将成为所有跟踪消息的接收者。所有后续调用都p/2
将导致消息发送到新启动的跟踪服务器。
以这种方式启动的跟踪服务器只会以格式化的方式在Erlang shell中显示跟踪消息(即使用io:format)。请参阅有关tracer/2
如何定制跟踪消息处理程序的说明。
要在远程节点上启动类似的跟踪器,请使用n/1
。
tracer(Type, Data) -> {ok, pid()} | {error, Error}
类型
该功能使用本地节点上的其他参数启动跟踪服务器。第一个参数,Type
表示跟踪消息是应由接收进程(process
),由跟踪器端口(port
)还是由跟踪器模块(module
)处理。有关示踪端口的描述,请参阅trace_port/2
示踪模块erl_tracer
。
如果Type
是process
,可以指定消息处理函数(HandlerSpec
)。处理函数应该是fun
两个参数,每个跟踪消息都会被调用,第一个参数包含消息,第二个参数包含上次调用fun
的返回值。第二个参数的初始值是在InitialData
部分中指定的HandlerSpec
。在HandlerFun
可以选择任何适当的行动调用时采取,并且可以通过返回其保存为下次调用的状态。
如果Type
是port
,则第二个参数应该是一个不带参数的乐趣
,并在调用时返回新打开的跟踪端口。这样的乐趣
最好是通过调用产生的trace_port/2
。
如果Type
是module
,则第二个参数应该是描述erl_tracer
模块用于跟踪,以及用于跟踪模块或返回相同元组的乐趣的状态。
如果返回错误,则可能是由于已经运行({error,already_started}
)的跟踪器服务器或由于HandlerFun
抛出异常造成的。
要在远程节点上启动类似的跟踪器,请使用tracer/3
。
tracer(Nodename, Type, Data) -> {ok, Nodename} | {error, Reason}
类型
这个函数相当于tracer/2
,但是作用于给定的节点。在节点(Nodename
)上启动一个跟踪器,并将该节点添加到跟踪节点列表中。
注
这个功能不等于n/1
。当n/1
启动一个将所有跟踪信息重定向到本地节点(即跟踪控制节点)上的进程跟踪器的进程跟踪器时,tracer/3
启动与跟踪控制节点上的跟踪器无关的任何类型的跟踪器。
有关详情,请参阅tracer/2
。
trace_port(Type, Parameters) -> fun()
类型
这个函数创建一个跟踪端口,生成乐趣
。的乐趣
不带任何参数,并返回一个新开的跟踪端口。该函数的返回值适合作为跟踪器/ 2的第二个参数,即dbg:tracer(port, dbg:trace_port(ip, 4711))
。
跟踪端口是一个Erlang端口,用于直接处理跟踪消息的驱动程序中的动态链接,而无需将其作为Erlang虚拟机中的消息发送。
两个跟踪司机正在落实,file
并ip
跟踪驱动程序。文件驱动程序将所有跟踪消息发送到一个或多个二进制文件,以后可以使用该trace_client/2
函数获取和处理它们。IP驱动程序将打开一个TCP / IP端口,用于监听连接。当客户端(最好通过调用trace_client/2
另一个Erlang节点启动时)连接时,所有跟踪消息都通过IP网络发送,以供远程客户端进一步处理。
使用跟踪端口可显着降低使用跟踪所带来的开销。
文件跟踪驱动程序需要一个文件名或换行文件规范作为参数。一个文件写入的缓冲程度很高,为什么所有的跟踪消息都不能
保证在系统崩溃的情况下保存在文件中。这是支付低追踪开销的代价。
换行文件规范用于限制跟踪消耗的磁盘空间。跟踪写入数量有限的文件,每个文件的大小有限。实际文件名是Filename ++ SeqCnt ++ Suffix
,其中SeqCnt
数从十进制字符串0
来WrapCnt
,然后从左右再次0
。当写入当前文件的跟踪项长于WrapSize
该文件关闭时,如果此封装跟踪中的文件数WrapCnt
与最旧文件一样多,则会打开一个新文件成为当前文件。因此,当一个换行跟踪被停止时,除了最后一个甚至可能为空的文件之外,最多WrapCnt
可以保存至少一个跟踪文件WrapSize
(但不会大得多)。默认值是WrapSize = 128*1024
and WrapCnt = 8
。
在SeqCnt
文件名中的值全部范围内0
通过WrapCnt
与在圆形序列的间隙。需要找到差距才能找到迹线的末端。
如果WrapSize
指定为{time, WrapTime}
,当当前文件已打开超过WrapTime
毫秒,不管它是否是空的。
IP跟踪驱动程序有一个QueSize
等待传递的消息队列。如果驱动程序无法按照运行时系统生成的速度一样快速发送消息,则会发送一条特殊消息,指示丢弃的消息数量。该消息将trace_client/3
作为元组{drop, N}
中指定的处理函数到达,其中N
是丢弃的连续消息的数量。在严重跟踪的情况下,drop可能发生,并且如果没有客户端正在读取跟踪消息,则肯定发生drop。默认值QueSize
是200。
flush_trace_port()
相当于flush_trace_port(node())
。
flush_trace_port(Nodename) -> ok | {error, Reason}
相当于trace_port_control(Nodename,flush)
。
trace_port_control(Operation)
相当于trace_port_control(node(),Operation)
。
trace_port_control(Nodename,Operation) -> ok | {ok, Result} | {error, Reason}
类型
此函数用于对给定节点(Nodename
)上的活动跟踪端口驱动程序执行控制操作。允许哪些操作以及它们的返回值取决于使用哪个跟踪驱动程序。
返回ok
或者{ok, Result}
如果操作成功,或者{error, Reason}
当前跟踪器是一个进程,或者它是不支持操作的端口。
的允许值Operation
是:
flush
该函数用于刷新由跟踪端口驱动程序持有的内部缓冲区。目前只有文件跟踪驱动程序支持此操作。退货ok
。
get_listen_port
返回{ok, IpPort}
这里IpPort
是驱动程序所使用的IP端口号监听套接字。只有ip跟踪驱动程序支持此操作。
trace_client(Type, Parameters) -> pid()
类型
该函数启动一个跟踪客户端,该客户端读取由跟踪端口驱动程序创建的输出,并以与该函数创建的跟踪程序大致相同的方式处理它tracer/0
。
如果Type
是file
,则客户端读取存储指定的文件中的所有跟踪消息Filename
或指定的WrapFilesSpec
(必须与创建跟踪时使用,见trace_port / 2),并让我们的默认处理函数的格式在控制台上的消息。这是通过文件跟踪端口驱动程序解释存储在文件中的数据的一种方法。
如果Type
是follow_file
,则客户端的行为与此类似file
,但会一直试图从文件中读取(并处理)更多数据,直到停止stop_trace_client/1
。WrapFilesSpec
不允许作为第二个参数Type
。
如果Type
是ip
,则客户端连接到PortNumber
主机上的TCP / IP端口Hostname
,从其中读取跟踪消息直到TCP / IP连接关闭。如果no Hostname
指定,则假定本地主机。
作为一个例子,我们可以让跟踪消息通过网络发送到另一个Erlang节点(最好不是
分布式的),在那里进行格式化:
在节点上stack
有一个Erlang节点ant@stack
,在shell中键入以下内容:
ant@stack> dbg:tracer(port, dbg:trace_port(ip,4711)).
<0.17.0>
ant@stack> dbg:p(self(), send).
{ok,1}
所有跟踪消息现在都会发送到跟踪端口驱动程序,后者又会监听TCP / IP端口4711上的连接。如果我们希望在另一个节点上(最好在另一个主机上)看到消息,我们的确如此:
-> dbg:trace_client(ip, {"stack", 4711}).
<0.42.0>
如果我们现在从节点上的shell发送消息ant@stack
,所有从外壳发送的信息都被追踪到:
ant@stack> self() ! hello.
hello
以下内容将出现在启动跟踪客户端的节点上的控制台上:
(<0.23.0>) <0.23.0> ! hello
(<0.23.0>) <0.22.0> ! {shell_rep,<0.23.0>,{value,hello,[],[]}}
最后一行是由于Erlang外壳中的内部消息传递而生成的。进程ID将会有所不同。
trace_client(Type, Parameters, HandlerSpec) -> pid()
类型
此函数的工作原理与trace_client/2
,但允许您编写自己的处理程序函数。处理程序函数的工作方式主要与tracer/2
,但也必须准备好处理窗体的跟踪消息。{drop, N}
,在哪里N
丢弃邮件的数量。只有在使用IP跟踪驱动程序时,才会出现此伪跟踪消息。
用于跟踪类型file
,伪跟踪消息end_of_trace
将出现在跟踪的末尾。在这种情况下,将忽略处理程序函数的返回值。
stop_trace_client(Pid) -> ok
类型
此函数关闭先前启动的跟踪客户端。大Pid
参数返回的进程id。trace_client/2
或trace_client/3
打电话。
get_tracer()
相当于get_tracer(node())
。
get_tracer(Nodename) -> {ok, Tracer}
类型
返回发送所有跟踪消息的进程、端口或跟踪器模块。
stop() -> ok
停止dbg
服务器并清除所有进程的所有跟踪标志和所有函数的所有本地跟踪模式。还关闭所有跟踪客户端并关闭所有跟踪端口。
请注意,此函数不影响全局跟踪模式。
stop_clear() -> ok
与STOP/0相同,但也清除全局函数调用上的所有跟踪模式。
简单示例-从shell跟踪
从Erlang shell进行跟踪的最简单方法是使用dbg:c/3
或者dbg:c/4
,例如跟踪该函数dbg:get_tracer/0
:
(tiger@durin)84> dbg:c(dbg,get_tracer,[]).
(<0.154.0>) <0.152.0> ! {<0.154.0>,{get_tracer,tiger@durin}}
(<0.154.0>) out {dbg,req,1}
(<0.154.0>) << {dbg,{ok,<0.153.0>}}
(<0.154.0>) in {dbg,req,1}
(<0.154.0>) << timeout
{ok,<0.153.0>}
(tiger@durin)85>
从shell进行跟踪
的另一种方法是明确启动一个跟踪器
,然后在要跟踪
的进程上设置您选择的跟踪标志
,例如跟踪
消息和进程事件:
(tiger@durin)66> Pid = spawn(fun() -> receive {From,Msg} -> From ! Msg end end).
<0.126.0>
(tiger@durin)67> dbg:tracer().
{ok,<0.128.0>}
(tiger@durin)68> dbg:p(Pid,[m,procs]).
{ok,[{matched,tiger@durin,1}]}
(tiger@durin)69> Pid ! {self(),hello}.
(<0.126.0>) << {<0.116.0>,hello}
{<0.116.0>,hello}
(<0.126.0>) << timeout
(<0.126.0>) <0.116.0> ! hello
(<0.126.0>) exit normal
(tiger@durin)70> flush().
Shell got hello
ok
(tiger@durin)71>
如果设置了call
跟踪
标志,则还必须为要跟踪
的功能设置跟踪模式
:
(tiger@durin)77> dbg:tracer().
{ok,<0.142.0>}
(tiger@durin)78> dbg:p(all,call).
{ok,[{matched,tiger@durin,3}]}
(tiger@durin)79> dbg:tp(dbg,get_tracer,0,[]).
{ok,[{matched,tiger@durin,1}]}
(tiger@durin)80> dbg:get_tracer().
(<0.116.0>) call dbg:get_tracer()
{ok,<0.143.0>}
(tiger@durin)81> dbg:tp(dbg,get_tracer,0,[{'_',[],[{return_trace}]}]).
{ok,[{matched,tiger@durin,1},{saved,1}]}
(tiger@durin)82> dbg:get_tracer().
(<0.116.0>) call dbg:get_tracer()
(<0.116.0>) returned from dbg:get_tracer/0 -> {ok,<0.143.0>}
{ok,<0.143.0>}
(tiger@durin)83>
高级主题-与seq结合[医]痕迹
该dbg
模块主要针对通过该erlang:trace/3
功能进行追踪。有时希望以更加微妙的方式跟踪消息,这可以在seq_trace
模块的帮助下完成。
seq_trace
实现顺序追踪(在AXE10世界中已知,有时称为“forlopp追踪”)。dbg
可以解释由seq_trace
这两种类型的跟踪生成的消息并且可以使用相同的跟踪器功能。这些seq_trace
消息甚至可以发送到跟踪端口进行进一步分析。
作为一个匹配规范可以打开连续跟踪,组合dbg
和seq_trace
可以说是相当强大的。这个简短的例子展示了一个使用顺序跟踪的会话:
1> dbg:tracer().
{ok,<0.30.0>}
2> {ok, Tracer} = dbg:get_tracer().
{ok,<0.31.0>}
3> seq_trace:set_system_tracer(Tracer).
false
4> dbg:tp(dbg, get_tracer, 0, [{[],[],[{set_seq_token, send, true}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}
5> dbg:p(all,call).
{ok,[{matched,nonode@nohost,22}]}
6> dbg:get_tracer(), seq_trace:set_token([]).
(<0.25.0>) call dbg:get_tracer()
SeqTrace [0]: (<0.25.0>) <0.30.0> ! {<0.25.0>,get_tracer} [Serial: {2,4}]
SeqTrace [0]: (<0.30.0>) <0.25.0> ! {dbg,{ok,<0.31.0>}} [Serial: {4,5}]
{1,0,5,<0.30.0>,4}
此会话将system_tracer设置为与普通跟踪器进程相同的进程(即<0.31.0>),并将函数的跟踪模式设置为dbg:get_tracer具有设置顺序令牌的操作。当函数被跟踪进程调用时(在这种情况下,所有进程都被跟踪),进程被令牌“污染”,seq_trace同时为服务器请求和响应发送消息。在seq_trace:set_token([])通话结束后清除seq_trace令牌,为什么当答案通过外壳到控制台端口传播任何消息被发送。否则输出会更加嘈杂。
注意警告
当在组长过程(IO过程)上跟踪函数调用时,存在导致死锁的风险。如果组长过程生成跟踪消息并且跟踪过程通过调用跟踪处理函数向同一组领导发送IO请求,则会发生这种情况。如果跟踪处理程序使用io
函数(例如)打印到tty,则只会发生该问题format/2
。请注意,dbg:p(all,call)
调用时,IO进程也会被跟踪。这是一个例子:
%% Using a default line editing shell
1> dbg:tracer(process, {fun(Msg,_) -> io:format("~p~n", [Msg]), 0 end, 0}).
{ok,<0.37.0>}
2> dbg:p(all, [call]).
{ok,[{matched,nonode@nohost,25}]}
3> dbg:tp(mymod,[{'_',[],[]}]).
{ok,[{matched,nonode@nohost,0},{saved,1}]}
4> mymod: % TAB pressed here
%% -- Deadlock --
这是另一个例子:
%% Using a shell without line editing (oldshell)
1> dbg:tracer(process).
{ok,<0.31.0>}
2> dbg:p(all, [call]).
{ok,[{matched,nonode@nohost,25}]}
3> dbg:tp(lists,[{'_',[],[]}]).
{ok,[{matched,nonode@nohost,0},{saved,1}]}
% -- Deadlock --
我们在第一个例子中遇到死锁的原因是,当按TAB来扩展函数名称时,组长(处理字符输入)调用mymod:module_info()
。这会生成跟踪消息,这反过来会导致跟踪器进程向组长发送IO请求(通过调用io:format/2
)。我们陷入僵局。
在第二个例子中,我们使用默认的跟踪处理函数。该处理程序通过向user
进程发送IO请求来打印到tty 。当Erlang以oldshell模式启动时,shell进程将具有user
组头,在这个例子中,tracer进程也是如此。由于在第一个IO请求被发送时,user
调用函数lists
最终会陷入死锁。
以下是关于如何避免死锁的一些建议:
- 不要跟踪示踪过程的小组负责人。如果所有进程的跟踪已打开,请致电
dbg:p(TracerGLPid,clear)
停止跟踪组长(TracerGLPid
)。process_info(TracerPid,group_leader)
告诉你这是哪个进程(TracerPid
从中返回dbg:get_tracer/0
)。
user
如果使用默认跟踪处理函数,则不要跟踪该进程。
- 在您自己的跟踪处理程序函数中,调用
erlang:display/1
而不是io
函数,或者如果user
未用作组长,则使用print来user
代替默认组领导。例如:io:format(user,Str,Args)
。