在一个并行的世界里面,我们很难做到单步断点调试来定位问题(太多的消息飞来飞去),Erlang设计者也深刻体会到这一点,推出了另一个trace机制。
通过这个trace,你可以:
.特定进程集内的函数调用输入输出,收发消息------trace 指定Processes{module,function,arity};
.特定端口集的输入输出,收发消息---------------trace 指定ports。
这样你就可以不加一行代码(抛弃那类io:format的烦琐又单一的方法吧),不影响正常运行的系统来(在一个服务器系统里面单步断点几乎是不可行的),就查看到你想要了解的控制流程。
 
现在Erlang用于Trace的库有:
• sys 是一个标准的OTP, 可以允许自 定义trace函数, 记录所有类型的事件等等。 它非常完善且可以很好地用于开发。 但它会稍微影响处于生产 环境的系统, 因为它没有把IO重定向到远程的shell中, 而且他没有限制trace消息的速度。 不过还是推荐阅读其文档模块。
dbg 也是一个标准的OTP。 它的接口在可用性方面显得有点笨拙。 但它完全足以满足你所需。 问 题在于: 你必须要知道你要做什么,因为 dbg可以记录一切, 并在2秒内把系统搞崩溃。
tracing BIFs作为一个Erang的模块可用。 它们大多作为原始块(the raw blocks)由这个列表中提到的application所调用,但由于他们处于较底层, 比较抽象, 用起来也非常困难。
redbug 是可以在正式的生产 运行系统中使用的trace库, 是eper 的一部分, 它内部有一个速度限制开关, 和一个不错
的可用接口。 为了使用它, 你必须把eper的所有依赖项都加上。 这个工具箱非常全面, 你会体验到一次非常有趣的安装。
recon_trace 是recon中负 责trace的模块。 目 的是和redbug有相同的安全水平,但却不要这么多的依赖项。 接口也不一样, 速度限制选项并不完全相同。 它可以只trace指定的函数调用, 没有trace send/recv message (实际在使用OTP的application里面根本没有必要支持trace message这种机制)
 
想要把上面的trace工具用起来,必须要掌握的基本概念。
我们要给trace指定目标:
. 指定trace的进程集;
. 指定模块中指定的函数的指定入参。
这两个加起来就的交集就是要trace的集合。
 
%%%         _,--------,_      _,--------,_
%%% ,-' `-,,-' `-,
%%% ,-' ,-' '-, `-,
%%% | Matching -' '- Matching |
%%% | Pids | Getting | Trace |
%%% | | Traced | Patterns |
%%% | -, ,- |
%%% '-, '-, ,-' ,-'
%%% '-,_ _,-''-,_ _,-'
%%% '--------' '--------'
%%%
接下来以最常用的dbg库来说明上面的这两个交集规则,其它库也是类似于此。

1.先从指定模块,函数,和参数开始:
> dbg:start().   % start dbg
> dbg:tracer(). % start a simple tracer process
> dbg:tp(Module, Function, Arity, []). % specify MFA you are interested in
> dbg:p(all, c). % trace calls (c) of that MFA for all processes. ... trace here > dbg:stop_clear().   % stop tracer and clear effect of tp and p calls.
你可以使用tp同时trace多个函数,如果你想trace模块中没有导出的函数,请使用tpl,
如果想移除trace就使用ctp或ctpl
> dbg:tpl(Module, '_', []).  % all calls in Module
> dbg:tpl(Module, Function, '_', []). % all calls to Module:Function with any arity.
> dbg:tpl(Module, Function, Arity, []). % all calls to Module:Function/Arity.
> dbg:tpl(M, F, A, [{'_', [], [{return_trace}]}]). % same as before, but also show return value.
你可以使用dbg:fun2ms来生成函数入参的匹配模式。
1> dbg:fun2ms(fun([M,N]) when N > 3 -> return_trace() end).
[{['$1','$2'],[{'>','$2',3}],[{return_trace}]}]
2.你可以使用dbg:p函数来指定特定的进程:
> dbg:p(all, c).   % trace calls to selected functions by all functions
> dbg:p(new, c). % trace calls by processes spawned from now on
> dbg:p(Pid, c). % trace calls by given process
> dbg:p(Pid, [c, m]). % trace calls and messages of a given process
dbg里面的函数都是对erlang:trace的封闭,erlang:trace太底层,接口非常难用,所以就封闭成了dbg库。
使用dbg要注意:
1.由于trace时产生的日志非常多,通常需要把它放到一个文件汇总后再分析(而不是直接输出到shell中):
   生成多个文件保存日志:
>dbg:tracer(port,dbg:trace_port(file,{"/log/trace",wrap,atom_to_list(node())})).
这点也说明了dbg太放纵使用者,一不小心就会产生大量的日志,导致节点异常。生产环境中慎用。
 
2.所有的tp,p都是在在dbg:start/0,dbg:trace/0开启后才能起作用的。

 
从上面可以看出:dbg把过滤进程,过滤{Module,Fun,Arity}分开处理。当然这样更加灵活,控制更精确。
 
但有那么一群人觉得dbg还不是很完善:
1.接口太过复杂,使用步骤复杂:start----》自定义的trace-----》stop;
2.没有输出日志次数控制,在生产环境中使用不当时会导致异常:不安全!
所以就有了上面介绍的redbug,recon_trace库。

下面介绍一下recon_trace库(他的使用是安全的!):
1.接口使用简单,他只需要调用一个函数calls/2 calls/3就可以trace;
2. 有次数限制和速度限制;
3.输出的trace比的默认的trace易读性强。
他把过滤进程集和模块函数过滤结合在一起啦!
calls/2 Equivalent to calls({Mod, Fun, Args},Max, []).
calls/3 Allows to set trace patterns and pid specifications to trace function calls.
clear/0 Stops all tracing at once.
 
这个库的接口都非常简单,用一次基本就上手啦,例子可以看这里
 
 

参考资料
 when i show tracing on a production node to someone who doesn’t know Erlang
 
[Erlang31]Erlang trace总结-LMLPHP

05-11 22:42