如何调试Erlang代码?

kupeojn6  于 2022-12-08  发布在  Erlang
关注(0)|答案(4)|浏览(195)

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.
Like in this Ruby example:

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

It's simple and fast - I just go to the line number 13 and fix the error.
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

There are no line numbers to look at.
And if I have two lines like

X = Param1,
Y = Param2,

in 'my_fun', how can understand in which line the problem lies?
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.
I have tried to add a lot of "io:format" lines in the code, but it is additional work which takes time.
I have also tried to use distel , but it requires 10 steps to just open a debugger once.
Questions:

  1. What is the most straight and simple way to debug Erlang code?
  2. Does Emacs' erlang-mode has something superior in terms of Erlang development comparing to Vim?
  3. What development 'write-compile-debug' cycle do you prefer? Do you leave Emacs to compile and run the code in the terminal? How do you search for errors in your Erlang code?
relj7zay

relj7zay1#

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

  • 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)

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).
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),

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)

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 .
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}}

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.
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.

lyfkaqu1

lyfkaqu12#

您可以使用Erlang debugger逐步执行程式码,并查看哪一行失败。
erl启动调试器,方法如下:

debugger:start().

然后,您可以使用UI或使用控制台(带有ii:

ii(my_module).

再次在UI或控制台中添加断点:

ib(my_module, my_func, func_arity).

同样,在Erlang R15中,我们最终会在堆栈跟踪中得到行号!

iq0todco

iq0todco3#

如果你用一个最新的erlang安装替换你的erlang安装,你会有行号,它们是从版本15开始添加的。
如果您的操作系统上还没有新版本,您可以从源代码构建或尝试从以下位置获取打包版本:http://www.erlang-solutions.com/section/132/download-erlang-otp

rpppsulh

rpppsulh4#

您可以在文件的编译时使用“debug_info”和“debugger”

1> c(test_module, [debug_info]).
{ok, test_module}
2> debugger:start().

有关如何在Erlang中调试的更多详细信息,您可以通过视频-https://vimeo.com/32724400的链接进行访问

相关问题