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

时间:2008-12-18 00:11:34

标签: 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

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

10 个答案:

答案 0 :(得分:206)

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

答案 1 :(得分:157)

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

puts caller

答案 2 :(得分:93)

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

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

答案 3 :(得分:45)

IRB设置了这个糟糕的“功能”,您可以自定义。

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

IRB.conf[:BACK_TRACE_LIMIT] = 100

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

有关IRB自定义的详细信息,请参阅Pickaxe book

答案 4 :(得分:9)

一个用于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

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

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

答案 5 :(得分:7)

这模仿官方的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',但位置正确。

答案 6 :(得分:3)

我在尝试加载测试环境(通过rake测试或自动测试)时遇到这些错误,并且IRB建议没有帮助。我最终将整个test / test_helper.rb包装在一个开始/救援块中并修复了问题。

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

答案 7 :(得分:1)

几乎每个人都回答了这个问题。我将任何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

答案 8 :(得分:0)

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

示例:一个线程正在迭代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射线)您实际拥有多少线程(相对于您认为有多少线程 - 通常这两个是不同的数字;)< / p>

答案 9 :(得分:-1)

您还可以使用backtrace Ruby gem(我是作者):

require 'backtrace'
begin
  # do something dangerous
rescue StandardError => e
  puts Backtrace.new(e)
end