web-dev-qa-db-ja.com

Rubyを取得して、切り捨てられたものの代わりに完全なバックトレースを出力するにはどうすればよいですか?

例外が発生した場合、多くの場合、コールスタックの奥深くからです。これが起こると、たいていの場合、実際の問題のコード行は私から隠されます:

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にダンプに完全なスタックを含めることを伝えるにはどうすればよいですか?

147

Exception#backtraceにはスタック全体が含まれています。

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

(ピータークーパーの Ruby Inside ブログに触発された)

215
Gareth

シンプルなワンライナーが必要な場合は、これを行うこともできます。

puts caller
159

これにより、エラーの説明と、きれいでインデントされたスタックトレースが生成されます。

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

IRBには、このひどい「機能」の設定があり、カスタマイズできます。

次の行を含む~/.irbrcというファイルを作成します。

IRB.conf[:BACK_TRACE_LIMIT] = 100

これにより、irbに少なくとも100個のスタックフレームが表示されます。非対話型ランタイムの同等の設定を見つけることができませんでした。

IRBのカスタマイズに関する詳細情報は Pickaxe book にあります。

45
robinluckey

コールスタック用のライナー:

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

すべての宝石なしのコールスタック用のライナー:

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

すべての宝石を含まない、現在のディレクトリに関連するコールスタック用の1つのライナー

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

これがあなたにとって重要な場合、これは公式の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」として報告しますが、場所は正しいです。

8
android.weasel

テスト環境を(rake testまたはautotestを介して)ロードしようとするとこれらのエラーが発生し、IRBの提案は役に立たなかった。結局、test/test_helper.rb全体をbegin/rescueブロックでラップしましたが、それで問題は解決しました。

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

backtrace Ruby gem(私は著者です)も使用できます。

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

[すべてのスレッドバックトレースを調べて原因を見つける]
複数のスレッドを使用する場合、完全に拡張されたコールスタックでさえ、実際の問題のコード行を隠すことができます!

例:1つのスレッドがRubyハッシュを繰り返しており、他のスレッドがそれを変更しようとしています。ブーム!例外!そして、「ビジー」ハッシュを変更しようとするときに取得するスタックトレースの問題は、ハッシュを変更しようとしている場所まで関数のチェーンを表示することですが、現在誰がそれを並列に反復しているかを表示しません(所有者)現在実行中のすべてのスレッドのスタックトレースを出力することで、これを把握する方法を次に示します。これを行う方法は次のとおりです。

# 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線のように)実際にいくつのスレッドを持っているかを示すことができるので、教育目的でも有用です(多くの場合、これらの2つは異なる数です)。

0