在一个并行的世界里面,我们很难做到单步断点调试来定位问题(太多的消息飞来飞去),Erlang设计者也深刻体会到这一点,推出了另一个trace机制。
通过这个trace,你可以:
1.特定进程集内的函数调用输入输出,收发消息------trace 指定Processes{module,function,arity}; 2.特定端口集的输入输出,收发消息---------------trace 指定ports。
这样你就可以不加一行代码(抛弃那类io:format的烦琐又单一的方法吧),不影响正常运行的系统来(在一个服务器系统里面单步断点几乎是不可行的),就查看到你想要了解的控制流程。
现在Erlang用于Trace的库有:
• sys comes standard with OTP and allows to set custom tracing functions, log all kinds of events, and so on. It’s generally complete and fine to use for development. It suffers a bit in production because it doesn’t redirect IO to remote shells, and doesn’t have rate-limiting capabilities for trace messages. It is still recommended to read the documentationfor the module.• dbg also comes standard with Erlang/OTP. Its interface is a bit clunky in terms of usability, but it’s entirely good enough to do what you need. The problem with it is that you have to know what you’re doing, because dbg can log absolutely everything on the node and kill one in under two seconds.• tracing BIFs are available as part of the erlang module. They’re mostly the raw blocks used by all the applications mentioned in this list, but their lower level of abstraction makes them rather difficult to use.• redbug is a production-safe tracing library, part of the eper 5 suite. It has an internal rate-limiter, and a nice usable interface. To use it, you must however be willing to add in all of eper’s dependencies. The toolkit is fairly comprehensive and can be a very interesting install.• recon_trace is recon’s take on tracing. The objective was to allow the same levels of safety as with redbug, but without the dependencies. The interface is different, and the rate-limiting options aren’t entirely identical. It can also only trace function calls, and not messages.
• 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指定目标:
1. 指定trace的进程集; 2. 指定模块中指定的函数的指定入参。
这两个加起来就的交集就是要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