it-swarm.com.de

Wie kann ich Ruby dazu bringen, einen vollständigen Backtrace statt eines abgeschnittenen zu drucken?

Wenn ich Ausnahmen bekomme, ist es oft tief im Aufrufstapel. Wenn dies passiert, wird mir die eigentliche fehlerhafte Codezeile meistens verborgen:

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

Diese "... 8 Stufen ..." macht mir viel Ärger. Ich habe nicht viel Erfolg beim googeln: Wie sage ich Ruby, dass ich will, dass Dumps den vollen Stack enthalten?

138

Ausnahme # backtrace enthält den gesamten Stapel:

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

(Inspiriert von Peter Coopers Ruby Inside Blog)

201
Gareth

Sie können dies auch tun, wenn Sie einen einfachen Einzeiler wünschen:

puts caller
153

Dies erzeugt die Fehlerbeschreibung und Nice Clean, eingerückter Stacktrace:

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

IRB hat eine Einstellung für diese schreckliche "Funktion", die Sie anpassen können.

Erstellen Sie eine Datei mit dem Namen ~/.irbrc, die die folgende Zeile enthält:

IRB.conf[:BACK_TRACE_LIMIT] = 100

Dadurch können Sie mindestens 100 Stack-Frames in irb sehen. Ich konnte keine entsprechende Einstellung für die nicht interaktive Laufzeit finden.

Detaillierte Informationen zur Anpassung des IRB finden Sie im Pickaxe-Buch .

43
robinluckey

Ein Liner für Callstack:

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

Ein Liner für Callstacks ohne alle Edelsteine:

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

Ein Liner für Callstacks ohne alle Edelsteine ​​und relativ zum aktuellen Verzeichnis

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

Dies ahmt die offizielle Ruby-Spur nach, wenn Ihnen das wichtig ist.

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

Komischerweise behandelt es nicht 'unbehandelte Exception' richtig und meldet es als 'RuntimeError', aber der Ort ist korrekt.

7
android.weasel

Ich habe diese Fehler erhalten, als ich versuchte, meine Testumgebung zu laden (über Rake-Test oder Autotest) und die IRB-Vorschläge haben nicht geholfen. Ich endete damit, den gesamten test/test_helper.rb in einen Anfangs-/Rettungsblock zu packen, und das hat alles behoben.

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

Sie können auch backtrace Ruby gem (Ich bin der Autor) verwenden:

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

[Untersuche alle Threads, um den Täter zu finden]
Selbst ein vollständig erweiterter Aufrufstapel kann die eigentliche fehlerhafte Codezeile vor Ihnen verbergen, wenn Sie mehr als einen Thread verwenden.

Beispiel: Ein Thread durchläuft Ruby Hash, ein anderer Thread versucht, ihn zu ändern. BOOM! Ausnahme! Das Problem mit der Stack-Ablaufverfolgung, die Sie erhalten, wenn Sie versuchen, 'busy' -Hash zu ändern, besteht darin, dass Sie die Funktionskette bis zu dem Ort zeigen, an dem Sie den Hash ändern möchten, aber er zeigt NICHT, wer ihn gerade parallel durchläuft ( Wem gehört es)! So können Sie dies herausfinden, indem Sie die Stapelablaufverfolgung für ALLE derzeit laufenden Threads drucken. So tun Sie das:

# 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

Das obige Code-Snippet ist sogar nur zu Lernzwecken nützlich, da es Ihnen (wie Röntgen) zeigen kann, wie viele Threads Sie tatsächlich haben (im Gegensatz zu den vielen, von denen Sie dachten, dass Sie sie haben - oft sind diese zwei unterschiedliche Zahlen;)

0