ฉันจะได้รับทับทิมเพื่อพิมพ์ backtrace เต็มแทนการตัดทอน?


170

เมื่อฉันได้รับการยกเว้นมักจะมาจากส่วนลึกภายใน call stack เมื่อสิ่งนี้เกิดขึ้นบ่อยกว่านั้นบรรทัดรหัสที่ละเมิดจริงจะถูกซ่อนไว้จากฉัน:

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 ระดับ ... " ทำให้ฉันมีปัญหาอย่างมาก ฉันไม่ประสบความสำเร็จในการทำ Google เป็นอันขาด: ฉันจะบอกทับทิมได้อย่างไรว่าฉันต้องการทิ้งให้รวมสแต็กเต็ม?


2
มีวิธีทำเช่นนี้จากบรรทัดคำสั่งแทนหรือไม่
Andrew Grimm

คำตอบ:


241

ข้อยกเว้น # 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ของ Peter Cooper's )


15
ฉันจะเพิ่มข้อยกเว้นอย่างน้อยก็เพื่อความสมบูรณ์ของตัวอย่าง
reto

13
คุณต้องพูดraiseออกไป ไม่จำเป็นต้องระบุการดำเนินการที่คุณต้องการเพิ่มอย่างชัดเจน
Timo

ดีฉันคิดเสมอว่าคุณต้องผ่านข้อยกเว้นก่อนหน้านี้เพื่อยกระดับ ฉันไม่ทราบว่าเป็นค่าเริ่มต้นสำหรับข้อยกเว้นล่าสุดที่ได้รับการช่วยเหลือ
ยกเลิกฟลอเรส

จะเกิดอะไรขึ้นถ้ารหัสของคุณไม่ส่งข้อยกเว้นคุณเพียงต้องการดูร่องรอยของสแต็คว่าเกิดจากที่ใด
Alex Levine

170

คุณสามารถทำเช่นนี้ได้หากคุณต้องการซับในที่เรียบง่าย:

puts caller

2
เคล็ดลับที่น่ากลัว ขอบคุณมาก. ฉันไม่รู้ว่าraiseสามารถใช้กับข้อโต้แย้งไม่ได้ ฉันก็ไม่รู้ว่าrescueจะได้รับการปฏิบัติอย่างถูกต้องในฐานะหนึ่งซับ ฉันยังเพิกเฉยต่อ vars โลกเหล่านั้นโดยสิ้นเชิงเช่น$!กัน
Dmytrii Nagirniak

11
ไม่จำเป็นต้องยก / ช่วยเหลือคุณเพียงแค่ใช้ Kernel # caller เช่นนี้:puts "this line was reached by #{caller.join("\n")}"
สตีเฟ่นซี

อาฉันรู้เรื่องนั้นไม่นานหลังจากโพสต์คำตอบนี้และลืมที่จะอัปเดต ขอบคุณ
คนขี้ขลาดนิรนาม

ฉันใช้y callerพิมพ์ผลลัพธ์เช่น Java stack trace
so_mv

caller(0,2)จะคืนค่าสองรายการล่าสุดใน stacktrace ดีสำหรับการแสดงผลกองซ้อนตัวย่อ
Magne

100

สิ่งนี้สร้างคำอธิบายข้อผิดพลาดและสะอาดดีสแต็คเทรซเยื้อง:

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

49

IRB มีการตั้งค่าสำหรับ "ฟีเจอร์" ที่น่ากลัวซึ่งคุณสามารถกำหนดเองได้

สร้างไฟล์ชื่อ~/.irbrcที่มีบรรทัดต่อไปนี้:

IRB.conf[:BACK_TRACE_LIMIT] = 100

สิ่งนี้จะช่วยให้คุณเห็นเฟรมสแต็คได้ 100 irbครั้งเป็นอย่างน้อย ฉันไม่สามารถค้นหาการตั้งค่าที่เทียบเท่าได้สำหรับรันไทม์ที่ไม่ต้องมีการโต้ตอบ

รายละเอียดข้อมูลเกี่ยวกับการปรับแต่งคณะกรรมการสามารถพบได้ในหนังสือเล่ม Pickaxe


3
นี่ควรเป็นคำตอบที่ได้รับการยอมรับเนื่องจากมันตอบคำถามว่าจะแสดง backtrace มากขึ้นแทนที่จะเป็น "... ระดับ X ... "
nickh

13

สายการบินหนึ่งสำหรับ callstack:

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

หนึ่งซับสำหรับการโทรติดต่อโดยไม่มีอัญมณีและสัมพัทธ์กับไดเรกทอรีปัจจุบัน

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

2
หนึ่งซับเป็นจริงสิ่งที่ไม่ดีเมื่อคุณมีหลายงบ
nurettin

3
@nurettin นี้สำหรับวัตถุประสงค์ในการแก้จุดบกพร่องอย่างรวดเร็วเพื่อทำให้มันเป็นหนึ่งบรรทัดทำให้ง่ายต่อการคัดลอกวางส่วนใหญ่อยู่ในเปลือกหอยโต้ตอบ
Dorian

@Dorian คุณเตือนฉันเกี่ยวกับคำถามที่ฉันมี: "ทำไมเชลล์แบบโต้ตอบมีประโยชน์หรือไม่ (ยกเว้น Shell-script)"
Sapphire_Brick

9

นี่เป็นการเลียนแบบรูบีทางการถ้ามันสำคัญกับคุณ

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' แต่ตำแหน่งถูกต้อง


ฉันเสียใจที่ฉันมี แต่หนึ่ง upvote ให้สำหรับคำตอบของคุณ ฉันเพิ่มสิ่งนี้ทุกที่
Dbz

4

ฉันได้รับข้อผิดพลาดเหล่านี้เมื่อพยายามโหลดสภาพแวดล้อมการทดสอบของฉัน (ผ่านการทดสอบเรคหรือการทดสอบอัตโนมัติ) และคำแนะนำของ IRB ไม่ได้ช่วยอะไร ฉันสิ้นสุดการทดสอบ / test_helper.rb ทั้งหมดของฉันในบล็อกเริ่มต้น / กู้ภัยและแก้ไขสิ่งนั้น

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

0

[ตรวจสอบ backtraces ของเธรดทั้งหมดเพื่อค้นหาผู้กระทำผิด]
แม้แต่สแต็คการโทรที่ขยายอย่างเต็มที่ยังสามารถซ่อนบรรทัดที่ไม่เหมาะสมของรหัสจากคุณเมื่อคุณใช้มากกว่าหนึ่งเธรด!

ตัวอย่าง: หนึ่งเธรดกำลังทำซ้ำ ruby ​​Hash เธรดอื่นกำลังพยายามแก้ไข BOOM! ข้อยกเว้น! และปัญหาของการติดตามสแต็กที่คุณได้รับในขณะที่พยายามแก้ไขแฮช 'ยุ่ง' ก็คือมันแสดงให้คุณเห็นห่วงโซ่ของฟังก์ชั่นลงไปยังสถานที่ที่คุณกำลังพยายามแก้ไขแฮช แต่มันไม่แสดงว่าใครกำลังทำซ้ำ ใครเป็นเจ้าของมัน)! ต่อไปนี้เป็นวิธีการคิดโดยการพิมพ์การติดตามสแต็กสำหรับเธรดที่กำลังรันอยู่ทั้งหมด นี่คือวิธีที่คุณทำ:

# 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

ข้อมูลโค้ดด้านบนมีประโยชน์แม้เพียงเพื่อการศึกษาเท่านั้นเพราะมันสามารถแสดงให้คุณเห็น (เช่นเอ็กซ์เรย์) ว่าคุณมีเธรดจำนวนเท่าใด (เทียบกับจำนวนที่คุณคิดว่าคุณมี - บ่อยครั้งที่สองนั้นเป็นตัวเลขที่แตกต่างกัน)


0

คุณยังสามารถใช้อัญมณี Ruby backtrace (ฉันเป็นผู้แต่ง):

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

4
อย่างน้อยคุณช่วยอธิบายได้ไหมว่าทำไมเราถึงต้องการใช้อัญมณีของคุณ? คุณสามารถแสดงตัวอย่างผลลัพธ์ได้ไหม
ioquatix
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.