如何让ruby打印完整的回溯而不是截断的?

Sni*_*gus 151 ruby exception stack-trace

当我得到异常时,它通常来自调用堆栈中的深层.当发生这种情况时,通常会对我隐藏实际有问题的代码行:

tmp.rb:7:in `t': undefined method `bar' for nil:NilClass (NoMethodError)
        from tmp.rb:10:in `s'
        from tmp.rb:13:in `r'
        from tmp.rb:16:in `q'
        from tmp.rb:19:in `p'
        from tmp.rb:22:in `o'
        from tmp.rb:25:in `n'
        from tmp.rb:28:in `m'
        from tmp.rb:31:in `l'
         ... 8 levels...
        from tmp.rb:58:in `c'
        from tmp.rb:61:in `b'
        from tmp.rb:64:in `a'
        from tmp.rb:67
Run Code Online (Sandbox Code Playgroud)

那个"... 8级......"截断给我带来了很多麻烦.我在这方面没有太大的成功:我怎么告诉ruby我想要转储包含完整的堆栈?

Gar*_*eth 223

异常#backtrace包含整个堆栈:

def do_division_by_zero; 5 / 0; end
begin
  do_division_by_zero
rescue => exception
  puts exception.backtrace
  raise # always reraise
end
Run Code Online (Sandbox Code Playgroud)

(灵感来自Peter Cooper的Ruby Inside博客)

  • 我会重新启动异常,至少为了示例completness. (13认同)
  • 要重新加注你只需要说"加注".无需明确指定要引发的execption. (10认同)

ano*_*ard 160

如果你想要一个简单的单行程,你也可以这样做:

puts caller
Run Code Online (Sandbox Code Playgroud)

  • 不需要提升/救援,你可以使用Kernel#caller,就像这样:`puts'这行是#{caller.join("\n")}"` (11认同)
  • 太棒了.非常感谢.我不知道`raise`可以在没有参数的情况下使用.我都不知道`救援'会被正确地当作一个班轮.我也完全忽略了像`$!`这样的全球变量. (2认同)
  • 但是,在 rake 任务的错误处理步骤(一个“rescue”块)中使用 `caller` 而不是 `e.backtrace` 不会为您提供被调用模型的堆栈跟踪,只是 rake 任务的堆栈跟踪,因此很没用.. (2认同)
  • 这个答案不适用于OP声明的用例,因为它显示了代码中的正确位置,而不是异常发生的位置。 (2认同)

小智 97

这会产生错误描述和漂亮的干净,缩进的堆栈跟踪:

begin               
 # Some exception throwing code
rescue => e
  puts "Error during processing: #{$!}"
  puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
end
Run Code Online (Sandbox Code Playgroud)


小智 46

IRB设置了这个可怕的"功能",您可以自定义.

创建一个名为~/.irbrc包含以下行的文件:

IRB.conf[:BACK_TRACE_LIMIT] = 100
Run Code Online (Sandbox Code Playgroud)

这将允许您irb至少看到100个堆栈帧.我无法找到非交互式运行时的等效设置.

有关IRB定制的详细信息可以在Pickaxe书中找到.

  • 这应该是公认的答案,因为它解决了如何显示更多的回溯而不是"...... X级......"的问题. (3认同)

Dor*_*ian 10

一个用于callstack的班轮:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end
Run Code Online (Sandbox Code Playgroud)

没有所有宝石的一个用于callstack的班轮:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//); end
Run Code Online (Sandbox Code Playgroud)

一个没有所有宝石和相对于当前目录的callstack的衬垫

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//).map { |l| l.gsub(`pwd`.strip + '/', '') }; end
Run Code Online (Sandbox Code Playgroud)

  • 当您有多个语句时,单行实际上是一件坏事。 (2认同)
  • @nurettin这是为了快速调试目的,所以使它成为一行可以很容易地复制粘贴它,主要是在交互式shell中 (2认同)

and*_*sel 8

如果这对你很重要,那就模仿官方的Ruby跟踪.

begin
  0/0  # or some other nonsense
rescue => e
  puts e.backtrace.join("\n\t")
       .sub("\n\t", ": #{e}#{e.class ? " (#{e.class})" : ''}\n\t")
end
Run Code Online (Sandbox Code Playgroud)

有趣的是,它没有正确处理'未处理的异常',将其报告为'RuntimeError',但位置是正确的.


小智 5

几乎所有人都回答了这个问题。我将任何 Rails 异常打印到日志中的版本是:

begin
    some_statement
rescue => e
    puts "Exception Occurred #{e}. Message: #{e.message}. Backtrace:  \n #{e.backtrace.join("\n")}"
    Rails.logger.error "Exception Occurred #{e}. Message: #{e.message}. Backtrace:  \n #{e.backtrace.join("\n")}"
end
Run Code Online (Sandbox Code Playgroud)