当我获得异常时,它通常来自调用堆栈的深处。当这种情况发生时,通常情况下,真正令人讨厌的代码行对我来说是隐藏的:

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

“…8级……”截断给我带来了很多麻烦。我在谷歌上搜索这个问题时没有取得多大的成功:我如何告诉ruby我想要转储包含完整的堆栈?


当前回答

IRB对这个糟糕的“特性”有一个设置,你可以自定义。

创建一个名为~/的文件。Irbrc,包括以下行:

IRB.conf[:BACK_TRACE_LIMIT] = 100

这将允许你在irb中至少看到100个堆栈帧。我还没有找到非交互式运行时的等效设置。

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

其他回答

Exception#backtrace包含了整个堆栈:

def do_division_by_zero; 5 / 0; end
begin
  do_division_by_zero
rescue => exception
  puts exception.backtrace
  raise # always reraise
end

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

IRB对这个糟糕的“特性”有一个设置,你可以自定义。

创建一个名为~/的文件。Irbrc,包括以下行:

IRB.conf[:BACK_TRACE_LIMIT] = 100

这将允许你在irb中至少看到100个堆栈帧。我还没有找到非交互式运行时的等效设置。

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

callstack的一行代码:

begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end

没有所有宝石的callstack的一行代码:

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

一个没有所有宝石和相对于当前目录的调用堆栈的一行代码

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

这模拟了官方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

有趣的是,它没有正确地处理“未处理的异常”,将其报告为“RuntimeError”,但位置是正确的。

这将产生错误描述和漂亮的、缩进的stacktrace:

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