如何调试 Erlang 代码? [英] How to debug Erlang code?

查看:22
本文介绍了如何调试 Erlang 代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些 Ruby 和 Java 背景,我习惯于在错误日志中有确切的行数.

I have some Ruby and Java background and I'm accustomed to having exact numbers of lines in the error logs.

所以,如果编译的代码有错误,我会在控制台输出中看到导致异常的行数.

So, if there is an error in the compiled code, I will see the number of line which caused the exception in the console output.

就像这个 Ruby 示例:

Like in this Ruby example:

my_ruby_code.rb:13:in `/': divided by 0 (ZeroDivisionError)
    from my_ruby_code.rb:13

它既简单又快速 - 我只需转到第 13 行并修复错误.

It's simple and fast - I just go to the line number 13 and fix the error.

相反,Erlang 只是这样说:

On the contrary, Erlang just says something like:

** exception error: no match of right hand side value [xxxx]
 in function my_module:my_fun/1
 in call from my_module:other_fun/2

没有要查看的行号.

如果我有两行像

X = Param1,
Y = Param2,

在'my_fun'中,如何知道问题出在哪一行?

in 'my_fun', how can understand in which line the problem lies?

此外,我曾尝试从 Vim 切换到 Emacs+Elang 模式,但到目前为止我获得的唯一好处是能够在 Emacs 中循环编译错误(C-k `).

Additionally, I have tried to switch to Emacs+Elang-mode from Vim, but the only bonus I've got so far is the ability to cycle through compilation errors inside Emacs (C-k `).

因此,编写代码并寻找右手边不匹配"等简单逻辑错误的过程似乎有点繁琐.

So, the process of writing code and seeking for simple logical errors like 'no match of right hand side' seems to be a bit cumbersome.

我尝试在代码中添加很多io:format"行,但这是额外的工作,需要时间.

I have tried to add a lot of "io:format" lines in the code, but it is additional work which takes time.

我也尝试过使用 distel,但它需要 10 个步骤才能打开调试器一次.

I have also tried to use distel, but it requires 10 steps to just open a debugger once.

问题:

  1. 调试 Erlang 代码最直接、最简单的方法是什么?
  2. 与 Vim 相比,Emacs 的 erlang 模式在 Erlang 开发方面有什么优势吗?
  3. 您更喜欢哪种开发编写-编译-调试"循环?您是否让 Emacs 在终端中编译和运行代码?你如何在你的 Erlang 代码中搜索错误?

推荐答案

调试 Erlang 代码有时会很棘手,尤其是处理 badmatch 错误.一般来说,要遵守的两个良好准则是:

Debugging Erlang code can be tricky at times, especially dealing with badmatch errors. In general, two good guidelines to keep are:

  • 保持函数简短
  • 如果可以的话,直接使用返回值,而不是绑定临时变量(这会给你带来获得 function_clause 错误等信息的好处)
  • Keep functions short
  • Use return values directly if you can, instead of binding temporary variables (this will give you the benefit of getting function_clause errors etc which are way more informative)

话虽如此,通常需要使用调试器来快速找到错误的根源.我建议使用命令行调试器 dbg,而不是图形调试器 debugger(当你知道如何使用它时会更快,而你没有从 Erlang shell 到 GUI 的上下文切换).

That being said, using the debuggers are usually required to quickly get to the bottom of errors. I recommend to use the command line debugger, dbg, instead of the graphical one, debugger (it's way faster when you know how to use it, and you don't have to context switch from the Erlang shell to a GUI).

鉴于您提供的示例表达式,情况通常是您将多个变量分配给其他变量(这在 Erlang 中绝对没有必要):

Given the sample expression you provided, the case is often that you have more than just variables being assigned to other variables (which is absolutely unnecessary in Erlang):

run(X, Y) ->
    X = something(whatever),
    Y = other:thing(more_data),

使用命令行调试器可以帮助在此处调试 badmatch 错误:

Debugging a badmatch error here is aided by using the command line debugger:

1> dbg:tracer().                            % Start the CLI debugger
{ok,<0.55.0>}
2> dbg:p(all, c).                           % Trace all processes, only calls
{ok,[{matched,nonode@nohost,29}]}
3> dbg:tpl(my_module, something, x).        % tpl = trace local functions as well
{ok,[{matched,nonode@nohost,1},{saved,x}]}
4> dbg:tp(other, do, x).                    % tp = trace exported functions  
{ok,[{matched,nonode@nohost,1},{saved,x}]}
5> dbg:tp(my_module, run, x).               % x means print exceptions
{ok,[{matched,nonode@nohost,1},{saved,x}]}  % (and normal return values)

在返回值中查找 {matched,_,1}... 如果返回值是 0 而不是 1 (或更多)这意味着没有函数匹配该模式.dbg 模块的完整文档可以在此处找到.

Look for {matched,_,1} in the return value... if this would have been 0 instead of 1 (or more) that would have meant that no functions matched the pattern. Full documentation for the dbg module can be found here.

鉴于 something/1other:do/1 总是返回 ok,可能会发生以下情况:

Given that both something/1 and other:do/1 always returns ok, the following could happen:

6> my_module:run(ok, ok).
(<0.72.0>) call my_module:run(ok,ok)
(<0.72.0>) call my_module:something(whatever)
(<0.72.0>) returned from my_module:something/1 -> ok
(<0.72.0>) call other:thing(more_data)
(<0.72.0>) returned from other:thing/1 -> ok
(<0.72.0>) returned from my_module:run/2 -> ok
ok

这里我们可以看到整个调用过程,以及给出了哪些返回值.如果我们用我们知道会失败的东西调用它:

Here we can see the whole call procedure, and what return values were given. If we call it with something we know will fail:

7> my_module:run(error, error).
** exception error: no match of right hand side value ok
(<0.72.0>) call my_module:run(error,error)
(<0.72.0>) call my_module:something(whatever)
(<0.72.0>) returned from my_module:something/1 -> ok
(<0.72.0>) exception_from {my_module,run,2} {error,{badmatch,ok}}

在这里我们可以看到我们得到了一个 badmatch 异常,something/1 被调用,但没有 other:do/1 所以我们可以推断出不匹配发生在该调用之前.

Here we can see that we got a badmatch exception, something/1 was called, but never other:do/1 so we can deduce that the badmatch happened before that call.

精通命令行调试器将为您节省大量时间,无论您是调试简单(但很棘手!)badmatch 错误还是更复杂的错误.

Getting proficient with the command line debugger will save you a lot of time, whether you debug simple (but tricky!) badmatch errors or something much more complex.

这篇关于如何调试 Erlang 代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆