使用 Redbug 跟踪 Erlang

在过去的一年半里,我一直在全职使用 Erlang 进行编程。当涉及到复杂的分布式应用程序时,我认为没有任何其他语言或框架可以击败它。就我而言,它最大的优点是能够跟踪代码和消息的执行,甚至可以跨集群中的节点。

常规的代码单步调试对于简单的程序非常有用,但要让代码在具有多核的不同机器上每秒执行数千个任务是不可能的。在 Erlang 中进行跟踪可以让您查看在哪些进程中使用哪些参数调用了哪些函数,以及它们之间传递了哪些消息。此功能开箱即用,甚至可以在生产系统中使用(如果您小心的话!)。

尽管跟踪是内置在 Erlang 中的,但最好的入门方法是使用eper中的 Redbug 库。我发现通过示例来解释 redbug 更容易。首先要记住的主要事情是它是自我说明的。只需在控制台中输入:

> redbug:help().

所以让我们开始吧。要跟踪任何 Erlang 进程中的函数调用,您可以使用如下内容:

1> redbug:start("lists:sort").
{30,2}
2> lists:sort([1,2,3,4]).
[1,2,3,4]

% 18:59:08 <0.32.0>({erlang,apply,2})
% lists:sort([1,2,3,4])
redbug done, timeout - 1
3>

这将启动 redbug 进程,该进程将运行 15 秒,并将通知您对列表模块中的排序函数进行的任何调用。迅速自行关闭是 redbug 的优点之一。跟踪的工作原理是从运行与我们的请求匹配的代码的进程向您启动 redbug 的进程发送消息。如果您在运行数千个瞬态 Erlang 进程的系统中指定常用函数,事情可能会很快失控,甚至导致节点崩溃。

其他类似的跟踪函数调用的方法是:

% Trace multiple functions at once
 1> redbug:start(["erlang:term_to_binary", "lists:sort"]).
 % Trace only the version of this function that takes 2 parameters
 2> redbug:start("erlang:term_to_binary/2"]).
 % Trace any function in the lists module
 3> redbug:start("lists").  

您还可以将跟踪限制为使用某些值作为参数调用的函数。例如:

% Only trace calls to lists:sort when it's passed the list [1,2,3]
 1> redbug:start("lists:sort([1,2,3]").

Erlang 的模式匹配可用于仅匹配某些参数,或仅匹配参数的某些部分。这里只跟踪以 3 作为第一个参数的 lists:member 的调用:

10> redbug:start("lists:member(3,_)").
{30,1}
11> lists:member(3, [1,2]).

% 19:18:45 <0.32.0>({erlang,apply,2})
% lists:member(3, [1,2])
false
12> lists:member(4, [1,2]).
false

您可以(并且应该!)对您的模式非常感兴趣。唉,redbug 目前不允许在二进制文件上进行匹配。但是你可以使用几乎任何你可以在 Erlang 函数中使用的守卫:

% Only match if the only argument is a binary of size 10
1> redbug:start("erlang:term_to_binary(B) when is_binary(B), size(B) == 10").
% Only if the argument is a list where the first element is greater than 9
2> redbug:start("lists:sort([A|_]) when A > 9").
% Only if the argument is a two tuple with 'tag' as the first element
3> redbug:start("erlang:term_to_binary({tag, _}).

有时您想知道跟踪的函数返回什么,或者在执行时获取堆栈跟踪。或者两者兼而有之:

1> redbug:start("lists:max->return").
2> redbug:start("lists:max->stack").
3> redbug:start("lists:max->return;stack").

如果你运行上面的例子并调用lists:max,你会看到它是一个递归函数。这意味着您可能会收到比预期更多的消息。幸运的是,redbug 会在收到一定数量的消息后自行关闭以保护您。您可以控制它的停留时间和它处理的最大消息数,如下所示:

% Process at most 1000 messages or
% stay up for 60 seconds, whatever happens first.
1> redbug:start(["lists->return", "erlang:term_to_binary/2->stack"],
     [{msgs, 1000}, {time, 60000}]).

其他参数可让您以许多有用的方式自定义 redbug。只需查看 redbug:help 了解详细信息。您可以将输出重定向到一个文件,使用正则表达式对其进行过滤,省略传递给跟踪函数的参数值,更改消息的大小限制(如果使用大量参数跟踪函数调用,redbug 也会关闭)等等。

在稍后的文章中,我们可以探索有关 redbug 和 Erlang 中底层跟踪机制的更多细节。尽管 redbug 很有用,但很多时候您需要完全访问跟踪原语。这通常意味着你遇到了很多麻烦:)。

Related Posts

2021 年你需要知道的关于 Erlang 的一切

今天,我们将看一个相当古老且有些古怪的东西。 你们大多数人可能没有注意到的语言。 虽然 Erlang 不像某些现代编程语言那样流行,但它安静地运行着 WhatsApp 和微信等每天为大量用户提供服务的应用程序。 在这篇文章中,我将告诉你关于这门语言的更多事情、它的历史,以及你是否应该考虑自己学习它。 ## 什么是 Erlang,它在哪里使用? Erl

Read More

Erlang JIT中基于类型的优化

这篇文章探讨了 Erlang/OTP 25 中基于类型的新优化,其中编译器将类型信息嵌入到 BEAM 文件中,以帮助JIT(即时编译器)生成更好的代码。 ## 两全其美 OTP 22 中引入的基于SSA的编译器处理步骤进行了复杂的类型分析,允许进行更多优化和更好的生成代码。然而,Erlang 编译器可以做什么样的优化是有限制的,因为 BEAM 文件必须

Read More

Erlang JIT之路

自从Erlang 存在,就一直有让它更快的需求和野心。这篇博文是一堂历史课,概述了主要的 Erlang 实现以及如何尝试提高 Erlang 的性能。 ## Prolog 解释器 Erlang 的第一个版本是在 1986 年在 Prolog 中实现的。那个版本的 Erlang 对于创建真正的应用程序来说太慢了,但它对于找出Erlang语言的哪些功能有用,哪

Read More