查看源代码 教程
可视化消息序列图
使用 ET
最简单的方法是将其用作显示消息序列图的图形工具。为此,您需要首先启动一个 Viewer
(默认情况下会启动一个 Collector
)。
{ok, ViewerPid} = et_viewer:start([{title,"Coffee Order"}]),
CollectorPid = et_viewer:get_collector_pid(ViewerPid).
然后,您可以使用函数 et_collector:report_event/6
将事件发送到 Collector
,如下所示:
et_collector:report_event(CollectorPid,85,from,to,message,extra_stuff).
Viewer
将自动从 Collector
拉取事件,并在屏幕上显示它们。
数字(在此示例中为 85)是一个从 1 到 100 的整数,用于指定消息的“详细级别”。数字越大,消息越重要。这提供了一种粗略的优先级过滤形式。
from
、to
和 message
参数的含义与它们的字面意思相同。from
和 to
在 Viewer
中被可视化为“生命线”,消息从一个传递到另一个。如果 from
和 to
的值相同,则它会作为“操作”显示在生命线旁边。extra_stuff
值只是您附加的数据,当有人在 Viewer
窗口中实际单击操作或消息时,将显示这些数据。
模块 et/examples/et_display_demo.erl
说明了如何使用它
-module(et_display_demo).
-export([test/0]).
test() ->
{ok, Viewer} = et_viewer:start([{title,"Coffee Order"}, {max_actors,10}]),
Drink = {drink,iced_chai_latte},
Size = {size,grande},
Milk = {milk,whole},
Flavor = {flavor,vanilla},
C = et_viewer:get_collector_pid(Viewer),
et_collector:report_event(C,99,customer,barrista1,place_order,[Drink,Size,Milk,Flavor]),
et_collector:report_event(C,80,barrista1,register,enter_order,[Drink,Size,Flavor]),
et_collector:report_event(C,80,register,barrista1,give_total,"$5"),
et_collector:report_event(C,80,barrista1,barrista1,get_cup,[Drink,Size]),
et_collector:report_event(C,80,barrista1,barrista2,give_cup,[]),
et_collector:report_event(C,90,barrista1,customer,request_money,"$5"),
et_collector:report_event(C,90,customer,barrista1,pay_money,"$5"),
et_collector:report_event(C,80,barrista2,barrista2,get_chai_mix,[]),
et_collector:report_event(C,80,barrista2,barrista2,add_flavor,[Flavor]),
et_collector:report_event(C,80,barrista2,barrista2,add_milk,[Milk]),
et_collector:report_event(C,80,barrista2,barrista2,add_ice,[]),
et_collector:report_event(C,80,barrista2,barrista2,swirl,[]),
et_collector:report_event(C,80,barrista2,customer,give_tasty_beverage,[Drink,Size]),
ok.
当您在上面的示例中运行 et_display_demo:test().
函数时,Viewer
窗口将如下所示:
四个模块
事件跟踪器框架由四个模块组成:
et
et_collector
et_viewer
et_selector
此外,您可能还需要熟悉 dbg
模块,以及可能的 seq_trace
模块。
事件跟踪器接口
et
模块与其他模块不同。它包含一个名为 et:trace_me/5
的函数。该函数本身没有任何实际作用。它的唯一目的是成为一个易于跟踪的函数。对它的调用可能如下所示:
et:trace_me(85,from,to,message,extra_stuff).
et:trace_me/5
的参数与上一章中的 et_collector:report_event/6
的参数相同。两者之间最大的区别在于这两个函数的语义。第二个函数实际上向 Collector
报告一个 Event
,而第一个函数什么也不做,它只是返回原子 hopefully_traced
。为了使 et:trace_me/5
的参数出现在 Collector
中,必须激活该函数的跟踪,并且必须将 Collector
注册为 Raw Trace Data
的 Tracer
。
Erlang 跟踪是一堆令人头疼的事情,它涉及对巧妙端口、跟踪返回格式和专门的跟踪 MatchSpecs
(它们实际上是它们自己特殊的地狱)的相当复杂的知识。跟踪机制确实非常强大,但可能很难掌握。
幸运的是,有一种简化的方法可以开始跟踪 et:trace_me/5
函数调用。其思想是,您应该在代码中战略性地使用对 et:trace_me/5
的调用,其中您的程序中有可用的有趣信息。然后,您只需启用全局跟踪来启动 Collector
:
et_viewer:start([{trace_global, true}, {trace_pattern, {et,max}}]).
这将启动一个 Collector
、一个 Viewer
,并开始跟踪 et:trace_me/5
函数调用。Raw Trace Data
由 Collector
收集,其视图由 Viewer
显示在屏幕上。您可以通过实现自己的 Filter
函数并在 Viewer
中注册它们来定义您自己的数据“视图”。
收集器和查看器
这两个组件协同工作。基本上,Collector
接收 Raw Trace Data
,并将其处理成 et
特定格式(在 et/include/et.hrl
中定义)的 Events
。Viewer
查询 Collector
并显示数据的交互式表示。
您可能想知道为什么它们不只是一个模块。Collector
是一个通用的、功能完善的框架,它允许进程“订阅”其收集的 Events
。一个 Collector
可以为多个 Viewers
提供服务。典型的情况是,您有一个 Viewer
以一种形式可视化 Events
,而另一个 Viewer
以另一种形式可视化它们。例如,如果您正在跟踪基于文本的协议(如 HTML
(或 Megaco/H.248
)),则能够以纯文本以及消息的内部表示形式显示 Events
会很有用。只要符合 Collector/Viewer
协议之间的协议,该架构还允许您实现自己的 Viewer
程序。目前存在两种类型的 Viewers
。即旧的基于 GS
的 Viewer
和新的基于 wxWidgets
的 Viewer
。但是如果您有兴趣,您可以实现自己的 Viewer
,例如,它可以将 Events
显示为 ASCII 艺术或任何您觉得有用的东西。
Viewer
默认情况下会为您创建一个 Collector
。通过一些选项和配置设置,您可以开始收集 Events
。
Collector
API 还允许您将收集的 Events
保存到文件,并在以后的会话中加载它们。
选择器
这可能是整个 et
套件中最核心的模块。Collector
需要“过滤器”将 Raw Trace Data
转换为它可以显示的“事件”。et_selector
模块提供默认的 Filter
和一些用于管理 Trace Pattern
的 API 调用。Selector
提供了实现以下功能的各种函数:
- 将
Raw Trace Data
转换为适当的Event
- 神奇地注意到
et:trace_me/5
函数的跟踪,并创建适当的Events
- 小心地防止两次转换
Raw Trace Data
- 管理
Trace Pattern
Trace Pattern
基本上是 module
和 detail level
(整数或原子 max 表示完整详细信息)的元组。在大多数情况下,Trace Pattern
{et,max}
就足够了。但是,如果您不希望 et
有任何运行时依赖项,您可以在某些模块中实现自己的 trace_me/5
函数,并在 Trace Pattern
中引用该模块。
您对 Viewer
的实例化指定的模块会传递到它自动创建的 Collector
,作为 Trace Pattern
存储,并最终进入 Selector
的内部。
您指定的模块(最终)会传递到 Selector
的默认 Filter
中。et:trace_me/5
函数调用的格式在该 Filter
中是硬编码的。
如何将它们组合在一起
Collector
会自动注册以侦听跟踪 Events
,因此您所要做的就是启用它们。
对于那些想要进行通用跟踪的人,请查阅 dbg
模块,了解如何跟踪您感兴趣的任何内容,并让它发挥其魔力。如果您只想让 et:trace_me/5
工作,请执行以下操作:
- 创建一个
Collector
- 创建一个
Viewer
(它可以为您完成步骤 1) - 启用并精简调试
模块 et/examples/et_trace_demo.erl
实现了这一点。
-module(et_trace_demo).
-export([test/0]).
test() ->
et_viewer:start([
{title,"Coffee Order"},
{trace_global,true},
{trace_pattern,{et,max}},
{max_actors,10}
]),
%% dbg:p(all,call),
%% dbg:tpl(et, trace_me, 5, []),
Drink = {drink,iced_chai_latte},
Size = {size,grande},
Milk = {milk,whole},
Flavor = {flavor,vanilla},
et:trace_me(99,customer,barrista1,place_order,[Drink,Size,Milk,Flavor]),
et:trace_me(80,barrista1,register,enter_order,[Drink,Size,Flavor]),
et:trace_me(80,register,barrista1,give_total,"$5"),
et:trace_me(80,barrista1,barrista1,get_cup,[Drink,Size]),
et:trace_me(80,barrista1,barrista2,give_cup,[]),
et:trace_me(90,barrista1,customer,request_money,"$5"),
et:trace_me(90,customer,barrista1,pay_money,"$5"),
et:trace_me(80,barrista2,barrista2,get_chai_mix,[]),
et:trace_me(80,barrista2,barrista2,add_flavor,[Flavor]),
et:trace_me(80,barrista2,barrista2,add_milk,[Milk]),
et:trace_me(80,barrista2,barrista2,add_ice,[]),
et:trace_me(80,barrista2,barrista2,swirl,[]),
et:trace_me(80,barrista2,customer,give_tasty_beverage,[Drink,Size]),
ok.
回顾上述内容,最重要的几点是:
- 启用全局跟踪
- 设置
Trace Pattern
- 告诉
dbg
跟踪函数调用 - 明确告诉它跟踪
et:trace_me/5
函数
当您运行上面的 et_trace_demo:test()
函数时,Viewer
窗口将如下面这个屏幕截图所示: