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

当我得到exception时,通常来自调用堆栈的内部。 当发生这种情况时,往往会出现实际违规的代码行,

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级……”的截尾给我带来了很大的麻烦。 我没有太多的成功googling这一个:我如何告诉ruby,我想转储包括完整的堆栈?

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博客启发)

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

 puts caller 

这产生了错误描述和很好的干净,缩进stacktrace:

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

IRB有一个可怕的“function”,您可以自定义设置。

创build一个名为~/.irbrc的文件,其中包含以下行:

 IRB.conf[:BACK_TRACE_LIMIT] = 100 

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

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

如果这对你很重要,这就模仿了官方的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 

有趣的是,它不会正确处理“未处理的exception”,将其报告为“RuntimeError”,但位置正确。

在尝试加载我的testing环境(通过raketesting或自动testing)时,我收到了这些错误,IRBbuild议没有帮助。 我结束了我的整个testing/ test_helper.rb在一个开始/救援块和固定的东西了。

 begin class ActiveSupport::TestCase #awesome stuff end rescue => e puts e.backtrace end 

一个class轮的callstack:

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

一个没有所有gem的堆栈的内存:

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

一个没有所有gem和相对于当前目录的调用堆栈

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

[检查所有的线程回溯find罪魁祸首]
即使是完全展开的调用堆栈,当您使用多个线程时,仍然可以隐藏实际违规的代码行!

例如:一个线程正在迭代ruby Hash,另一个线程正在尝试修改它。 繁荣! 例外! 在尝试修改“繁忙”散列时,堆栈跟踪的问题在于它向您显示了函数链,直到您试图修改散列的地方,但是它不显示当前谁正在并行迭代它(谁拥有它)! 通过打印所有当前正在运行的线程的堆栈跟踪来解决这个问题。 这是你如何做到这一点:

 # This solution was found in comment by @thedarkone on https://github.com/rails/rails/issues/24627 rescue Object => boom thread_count = 0 Thread.list.each do |t| thread_count += 1 err_msg += "--- thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace begin \n" # Lets see if we are able to pin down the culprit # by collecting backtrace for all existing threads: err_msg += t.backtrace.join("\n") err_msg += "\n---thread #{thread_count} of total #{Thread.list.size} #{t.object_id} backtrace end \n" end # and just print it somewhere you like: $stderr.puts(err_msg) raise # always reraise end 

上面的代码片段甚至仅仅用于教育目的是有用的,因为它可以向你展示(比如X射线)你实际拥有多less线程(与你认为你有多less线程 – 通常这两个线程是不同的数字)。