查看源码 描述

概述

事件跟踪器 (ET) 工具的两个主要组件是图形序列图查看器 (et_viewer) 及其后备存储 (et_collector)。一个 收集器 可以作为多个同时运行的 查看器 的后备存储,其中每个查看器可以显示相同跟踪数据的不同视图。

收集器 和其 查看器 之间的接口是公开的,以便支持其他类型的 查看器。但是,在以下文本中,我们将重点介绍 et_viewer 的用法。

主要的启动函数是 et_viewer:start/1。默认情况下,它会同时启动一个 et_collector 和一个 et_viewer

% erl -pa et/examples
Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1> {ok, Viewer} = et_viewer:start([]).
{ok,<0.40.0>}

一个 查看器 通过定期轮询其 收集器 以获取更多要显示的 事件,从而从收集器获取跟踪 事件。例如,使用 et_collector:report_event/6事件 报告给 收集器

2> Collector = et_viewer:get_collector_pid(Viewer).
<0.39.0>
3> et_collector:report_event(Collector, 60, my_shell, mnesia_tm, start_outer,
3>                           "Start outer transaction"),
3> et_collector:report_event(Collector, 40, mnesia_tm, my_shell, new_tid,
3>                           "New transaction id is 4711"),
3> et_collector:report_event(Collector, 20, my_shell, mnesia_locker, try_write_lock,
3>                           "Acquire write lock for {my_tab, key}"),
3> et_collector:report_event(Collector, 10, mnesia_locker, my_shell, granted,
3>                           "You got the write lock for {my_tab, key}"),
3> et_collector:report_event(Collector, 60, my_shell, do_commit,
3>                           "Perform  transaction commit"),
3> et_collector:report_event(Collector, 40, my_shell, mnesia_locker, release_tid,
3>                           "Release all locks for transaction 4711"),
3> et_collector:report_event(Collector, 60, my_shell, mnesia_tm, delete_transaction,
3>                           "End of outer transaction"),
3> et_collector:report_event(Collector, 20, my_shell, end_outer,
3>                           "Transaction returned {atomic, ok}").
{ok,{table_handle,<0.39.0>,16402,trace_ts,
     #Fun<et_collector.0.62831470>}}

这实际上是对由 Mnesia 事务引起的进程 事件 的模拟,该事务在本地表中写入记录。

mnesia:transaction(fun() -> mnesia:write({my_tab, key, val}) end).

在这个阶段,当我们有几个 事件 时,是时候展示它在 et_viewer 的图形界面中的样子了。

A simulated Mnesia transaction which writes one record

在序列图中,参与者(象征性地执行了 事件 的实体)显示为命名的垂直条。可以通过拖动(在操作期间按住鼠标左键)参与者的名称标签并将其放置在其他位置来更改参与者的顺序。

Two actors has switched places

事件 可以是由单个参与者执行的操作(蓝色文本标签),也可以涉及两个参与者,然后被描绘为从一个参与者指向另一个参与者的箭头(红色文本标签)。可以通过单击(按下并释放鼠标左键)事件标签文本或箭头来显示 事件 的详细信息。执行此操作时,会弹出一个 内容查看器 窗口。它可能看起来像这样

Details of a write lock message

过滤器和字典

事件跟踪器 (ET) 在各种上下文中使用命名过滤器。事件跟踪过滤器是一个 Erlang fun,它将一些跟踪数据作为输入,并返回其可能修改后的版本。

filter(TraceData) -> false | true | {true, NewEvent}

TraceData = Event | erlang_trace_data()
Event = #event{}
NewEvent = #event{}

过滤器函数的接口与旧的 lists:filtermap/2 的过滤器函数相同。如果过滤器返回 false,则表示应静默丢弃跟踪数据。true 表示跟踪数据已经是一个 事件记录,并且应保持原样。true 表示 TraceData 已经是一个 事件记录,并且应保持原样。{true, NewEvent} 表示原始跟踪数据应替换为 Event。这提供了摆脱不需要的 事件 以及启用 事件 的替代视图的方法。

跟踪数据暴露的第一个过滤器是 收集器过滤器。当使用 et_collector:report/2(或 et_collector:report_event/5,6)报告跟踪 事件 时,首先发生的事情是,向 收集器 进程发送消息,以获取包含一些有用的东西的句柄,例如 收集器过滤器 Fun 和 Ets 表标识符。然后,应用 收集器过滤器 Fun,如果它返回 true(或 {true, NewEvent}),则 事件 将存储在 Ets 表中。作为优化,后续调用 et_collector:report 函数可以直接使用句柄,而不是 收集器 Pid

所有过滤器(在 收集器查看器 中注册)都必须能够处理作为输入的 事件记录收集器过滤器(即名为 all 的过滤器)有点特殊,因为它的输入也可能是原始的 Erlang 跟踪数据

收集器 管理一个基于键/值的字典,其中存储了过滤器。字典的更新会传播到所有订阅进程。当启动 查看器 时,它会注册为字典更新的订阅者。

在每个 查看器 中,只有一个过滤器处于活动状态,并且 查看器收集器 获取的所有跟踪 事件 都将通过该过滤器。通过编写巧妙的过滤器,可以自定义 事件 在查看器中的外观。et/examples/et_demo.erl 中的以下过滤器替换了参与者名称 mnesia_tmmnesia_locker,并保持记录中的其他所有内容不变。


mgr_actors(E) when is_record(E, event) ->
    Actor = fun(A) ->
               case A of
                   mnesia_tm     -> trans_mgr;
                   mnesia_locker -> lock_mgr;
                   _             -> A
               end
            end,
    {true, E#event{from = Actor(E#event.from),
                   to = Actor(E#event.to),
                   contents = [{orig_from, E#event.from},
                               {orig_to,   E#event.to},
                               {orig_contents, E#event.contents}]}}.

如果现在将过滤器添加到正在运行的 收集器

4> Fun = fun(E) -> et_demo:mgr_actors(E) end.
#Fun<erl_eval.6.13229925>
5> et_collector:dict_insert(Collector, {filter, mgr_actors}, Fun).
ok

您将看到所有查看器中的 过滤器 菜单都有一个名为 mgr_actors 的新条目。选择它,一个新的 查看器 窗口将弹出。

The same trace data in a different view

为了查看 事件 的详细信息,您可以单击 事件 以启动该 事件内容查看器。在 内容查看器 中,还有一个过滤器菜单,可以从查看器中选择的视图之外的其他视图检查 事件。单击 new_tid 事件 将弹出一个 内容查看器 窗口,显示 mgr_actors 视图中的 事件

The trace Event in the mgr_actors view

过滤器 菜单中选择 all 条目,一个新的 内容查看器窗口 将弹出,显示收集器视图中的相同跟踪 事件

The same trace Event in the collectors view

跟踪客户端

如您所见,可以显式使用 et_collector:report_event/5,6 函数。通过使用这些函数,您可以编写自己的跟踪客户端,该客户端从以任何格式存储的任何源读取跟踪数据,并将其提供给 收集器。您可以将默认的 收集器过滤器 替换为一个过滤器,该过滤器将新的令人兴奋的跟踪数据格式转换为 事件记录,或者您可以在调用 et_collector:report/2 之前将其转换为 事件记录,然后依靠默认的 收集器过滤器 来处理新格式。

API 中还有一些现有函数可以从各种源读取并调用 et_collector:report/2

  • 收集器 托管的跟踪 事件 可以存储到文件中,然后通过在 查看器文件 菜单中选择 保存加载 条目或通过 et_collector API 加载。

  • 还可以通过利用 Erlang 模拟器中的内置跟踪支持来对正在运行的系统执行实时跟踪。可以将这些 Erlang 跟踪定向到文件或端口。有关更多信息,请参阅 erlang:trace/3erlang:trace_pattern/3dbgttb 的参考手册。

    还有相应的跟踪客户端类型可以从这些文件或端口读取 Erlang 跟踪数据格式。et_collector:start_trace_client/3 函数使用这些 Erlang 跟踪客户端,并将跟踪数据重定向到 收集器

    默认的 收集器过滤器 将原始 Erlang 跟踪数据格式转换为 事件记录。如果您想以不同的方式执行此操作,当然可以从头开始编写自己的 收集器过滤器。但是,如果您先在 et_selector:parse_event/2 中应用默认过滤器,然后再应用自己的输出转换,可能会节省您一些精力。

全局跟踪

在一组节点上设置 Erlang 跟踪器并将跟踪客户端连接到这些跟踪器的端口并不直观。为了使其更容易,事件跟踪器 具有全局跟踪的概念。使用时,et_collector 进程将监视 Erlang 节点,当一个节点连接时,将自动在新连接的节点上启动 Erlang 跟踪器。还将在 收集器 节点上启动相应的跟踪客户端,以便自动将跟踪 事件 转发到 收集器。将布尔参数 trace_global 设置为 true,以便为 et_collectoret_viewer 激活全局跟踪。您可以拥有多少个并发(匿名)收集器没有限制,但您只能拥有一个全局 收集器,因为它的名称在 global 中注册。

为了进一步简化追踪,您可以使用 et:trace_me/4,5 函数。这些函数旨在当您的应用程序中出现需要突出显示的有趣 事件 时,从其他应用程序调用。这些函数非常轻量级,除了返回一个原子之外什么也不做。这些函数专门设计用于追踪。由于调用者显式地提供了 事件记录 字段的值,因此默认的 收集器过滤器 能够自动提供自定义的 事件记录,而无需任何用户定义的过滤器函数。

在正常操作中,et:trace_me/4,5 调用几乎是免费的。当需要追踪时,您可以显式地激活对这些函数的追踪。或者,您可以将 trace_global 的使用与 trace_pattern 的使用相结合。设置后,trace_pattern 将自动在所有连接的节点上激活。

trace_pattern 的一个好处是,它提供了一种非常简单的方法,通过允许您显式控制追踪的详细程度来最大限度地减少生成的追踪数据量。您可能已经看到 et_viewer 有一个名为 “详细程度” 的滑块,允许您控制在 查看器 中显示的追踪 事件 的详细程度。另一方面,如果您在 trace_pattern 中设置较低的详细程度,则很多追踪数据将永远不会生成,因此不会通过套接字发送到追踪客户端并存储在 收集器 中。

查看器窗口

et_viewer 中可用的几乎所有功能也可以通过快捷方式使用。与选择菜单项具有相同效果的键在括号中显示。例如,按键 r 等同于选择菜单项 查看器->刷新

文件菜单

  • 清除收集器中的所有事件 - 删除存储在 收集器 中的所有 事件,并通知所有连接的 查看器
  • 从文件加载事件到收集器 - 从文件加载 事件收集器,并通知所有连接的 查看器
  • 将收集器中的所有事件保存到文件 - 将存储在 收集器 中的所有 事件 保存到文件。
  • 打印设置 - 允许编辑打印机设置,例如纸张和布局。
  • 打印当前页 - 打印当前页上的事件。页面大小取决于所选的纸张类型。
  • 打印所有页 - 打印所有事件。页面大小取决于所选的纸张类型。
  • 关闭此查看器 - 关闭此 查看器 窗口,但保留所有其他 查看器 窗口和 收集器 进程。
  • 关闭其他查看器,但保留此查看器 - 保留此 查看器 窗口及其 收集器 进程,但关闭所有其他连接到同一 收集器查看器 窗口。
  • 关闭所有查看器和收集器 - 关闭 收集器 以及所有连接到它的 查看器

查看器菜单

  • 第一个 - 将 查看器滚动到 收集器 中的第一个 事件
  • 最后一个 - 将 查看器滚动到 收集器 中的最后一个 事件
  • 上一个 - 将 查看器向后滚动一页。
  • 下一个 - 将 查看器向前滚动一页。
  • 刷新 - 清除 查看器并从 收集器 重新读取其 事件
  • 向上 - 向后滚动几个 事件
  • 向下 - 向前滚动几个 事件
  • 显示所有参与者。 - 重置隐藏和/或突出显示的参与者的设置。

收集器菜单

  • 第一个 - 将所有 查看器滚动到 收集器 中的第一个 事件
  • 最后一个 - 将 所有 查看器滚动到 收集器 中的最后一个 事件
  • 上一个 - 将 所有 查看器向后滚动一页。
  • 下一个 - 将 所有 查看器向前滚动一页。
  • 刷新 - 清除 所有 查看器并从 收集器 重新读取它们的 事件

过滤器和缩放菜单

  • 活动过滤器 (=) - 启动一个新的 查看器 窗口,其活动过滤器和缩放与当前窗口相同。
  • 活动过滤器 (+) - 启动一个新的 查看器 窗口,其活动过滤器与当前窗口相同,但缩放比例更大。
  • 活动过滤器 (-) - 启动一个新的 查看器 窗口,其活动过滤器与当前窗口相同,但缩放比例更小。
  • 全部 (0) - 启动一个新的 查看器,其活动过滤器为 收集器过滤器。这将导致查看收集器中的所有事件。
  • 另一个过滤器 (2) - 如果在字典中插入了更多过滤器,这些过滤器将在此处显示为 过滤器 菜单中的条目。第二个过滤器将获得快捷方式编号 2,下一个过滤器获得编号 3,依此类推。名称是排序的。

滑块和单选按钮

  • 隐藏自=至 - 如果为真,则表示 查看器 将隐藏所有 from-actor 等于 to-actor 的 事件。这些事件有时称为动作。
  • 隐藏(排除的参与者) - 如果为真,则表示 查看器 将隐藏所有参与者被标记为排除的 事件。排除的参与者通常在 查看器 中显示时用圆括号括起来。
  • 详细程度 - 此滑块控制 查看器 的分辨率。仅显示详细程度 小于 所选级别(默认=100=最大)的 事件

其他功能

  • 垂直滚动 - 使用鼠标滚轮和向上/向下箭头进行少量滚动。使用向上/向下翻页和 Home/End 按钮进行更多滚动。
  • 显示事件的详细信息 - 左键单击事件标签或箭头,将弹出一个新的 内容查看器 窗口,显示 事件 的内容。
  • 突出显示参与者(切换) - 左键单击参与者名称标签。参与者名称将用方括号 [] 括起来。当一个或多个参与者被突出显示时,仅显示与这些参与者相关的事件。所有其他参与者将被隐藏。
  • 排除参与者(切换) - 右键单击参与者名称标签。参与者名称将用圆括号 () 括起来。当一个参与者被排除时,与此参与者相关的所有事件将被隐藏。如果选中复选框 隐藏(排除的参与者),则甚至会隐藏排除的参与者的名称标签和相应的垂直线。
  • 移动参与者 - 左键单击并拖动参与者名称标签。通过首先单击参与者名称,按住按钮,同时将光标移动到新位置,然后在要移动参与者的位置释放按钮来移动参与者。
  • 显示所有参与者 - 按“a”按钮。重置隐藏和/或突出显示的参与者的设置。

配置

Ets 表中的 事件记录 按时间戳排序。应使用哪个时间戳由 event_order 参数控制。默认值为 trace_ts,表示生成跟踪数据的时间。event_ts 表示解析跟踪数据(转换为 事件记录)的时间。

内容查看器窗口

文件菜单

  • 关闭 - 关闭此窗口。
  • 保存 - 将此窗口的内容保存到文件。

过滤器菜单

  • 活动过滤器 - 启动一个新的 内容查看器窗口,其活动过滤器相同。
  • 另一个过滤器 (2) - 如果在字典中插入了更多过滤器,这些过滤器将在此处显示为 过滤器 菜单中的条目。第二个过滤器将为编号 2,下一个过滤器为编号 3,依此类推。名称是排序的。

隐藏菜单

  • 在查看器中隐藏参与者 - 已知的参与者在 查看器 窗口中显示为命名的垂直条。通过隐藏参与者,其垂直条将被删除,并且 查看器 将被刷新。

    只有在达到 max_actors 阈值时,隐藏参与者 才有意义,因为它会暗示“隐藏”的参与者将显示为 “未知”。如果未达到 max_actors 阈值,则参与者将重新以垂直条的形式出现在 查看器 中。

  • 在查看器中显示参与者 - 这表示将该参与者作为已知参与者添加到 查看器 中,并带有其自己的垂直条。

搜索菜单

  • 从该事件向前搜索 - 将此事件设置为查看器中的第一个事件,并将其显示模式更改为进入向前搜索模式。此事件的参与者(from、to 或两者)将被添加到选定参与者列表中。
  • 从该事件反向搜索 - 将此事件设置为 查看器 中的第一个 事件,并将其显示模式更改为进入反向搜索模式。此 事件 的参与者(from、to 或两者)将被添加到选定参与者列表中。请注意,事件 将以相反的顺序显示。
  • 中止搜索。显示所有 - 将 查看器 的显示模式切换为显示所有 事件,而无需考虑任何正在进行的搜索。中止搜索。