รับการติดตามสแต็กปัจจุบันใน Ruby โดยไม่เพิ่มข้อยกเว้น


141

ฉันต้องการบันทึก backtrace ปัจจุบัน (stacktrace) ในแอพ Rails 3 โดยไม่มีข้อยกเว้นเกิดขึ้น มีความคิดอย่างไร

ทำไมฉันถึงต้องการสิ่งนี้ ฉันกำลังพยายามติดตามการโทรที่เกิดขึ้นเมื่อ Rails ค้นหาเทมเพลตเพื่อที่ฉันจะได้เลือกส่วนหนึ่งของกระบวนการที่จะลบล้าง (เพราะฉันต้องการเปลี่ยนเส้นทางการดูสำหรับคอนโทรลเลอร์คลาสย่อยของฉัน)

ฉันต้องการเรียกมันจากไฟล์: gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb. ฉันรู้ว่านั่นไม่ใช่แนวทางปฏิบัติที่ดีที่สุด แต่ฉันรู้ว่ามันเป็นดาวน์สตรีมของสแต็กจากที่ที่เกิดการค้นหาเทมเพลต


4
วิธีการแก้ปัญหาสกปรก: e.backtraceเพิ่มข้อยกเว้นมีการช่วยเหลือได้ทันทีและเข้าสู่ระบบ ฉันเคยเห็นมันในโครงการหนึ่งที่ฉันทำงานด้วย ไม่ใช่แนวทางที่ดีที่สุด แต่ใช้ได้ผล หวังว่าจะได้ยินทางออกที่ดีกว่าจากคนอื่นแม้ว่า
KL-7

คำตอบ:


186

คุณสามารถใช้Kernel#caller:

# /tmp/caller.rb

def foo 
  puts caller # Kernel#caller returns an array of strings
end

def bar 
  foo 
end

def baz 
  bar 
end

baz

เอาท์พุต:

caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'

ไม่ใช่Kernel.caller- มีจุด? Kernel.new.callerไม่ได้กำหนดไว้ที่นี่
ecoologic

8
ไม่ในทางเทคนิคcallerเป็นวิธีการของอินสแตนซ์ เนื่องจากKernelโมดูลรวมอยู่ในทุกคลาส Ruby (ยกเว้นBasicObjectใน 1.9) จึงมีให้ใช้งานเป็นวิธีการอินสแตนซ์บนวัตถุใด ๆ (แม้ว่าจะเป็นแบบส่วนตัว) คุณไม่สามารถเรียกได้ว่าเป็นKernel.new.callerเพียงเพราะคุณไม่สามารถสร้างอินสแตนซ์โมดูลได้ (ไม่มีnewวิธีการ)
KL-7

อันนี้รองรับพารามิเตอร์เพื่อข้ามผู้โทรจำนวนเท่าใดก็ได้ ดู: stackoverflow.com/a/3829269/520567
akostadinov

7
สำหรับการใช้งานพิมพ์สวย ๆ - Rails.logger.debug caller.join("\n")หรือputs caller.join("\n"). ขอบคุณ.
Jignesh Gohel

20

ลองใช้

Thread.current.backtrace

1
ข้อได้เปรียบของคำตอบนี้คือมีวิธีการปัจจุบันใน backtrace ในขณะKernel#callerที่วิธีการปัจจุบันออกไป เช่นMyClass.new.returns_caller => ["(irb):42:in 'irb_binding'",...] ไม่มีประโยชน์เท่า MyClass.new.returns_thread_backtrace => ["(irb):38:in 'backtrace'","(irb):38:in 'returns_thread_backtrace'","(irb):43:in 'irb_binding'",...]
stwr667

6

ฉันใช้สิ่งนี้เพื่อแสดงหน้าข้อผิดพลาดที่กำหนดเองเมื่อมีการเพิ่มข้อยกเว้น

rescue_from Exception do |exception|
  logger.error exception.class
  logger.error exception.message
  logger.error exception.backtrace.join "\n"
  @exception = exception


  # ExceptionNotifier::Notifier.exception_notification env, @exception

  respond_to do |format|
    if [AbstractController::ActionNotFound, ActiveRecord::RecordNotFound, ActionController::RoutingError, ActionController::UnknownAction].include?(exception.class)
      format.html { render :template => "errors/404", :status => 404 }
      format.js   { render :nothing => true, :status => 404 }
      format.xml  { render :nothing => true, :status => 404 }
    elsif exception.class == CanCan::AccessDenied
      format.html {
        render :template => "errors/401", :status => 401 #, :layout => 'application'
      }
      # format.js   { render :json => { :errors => [exception.message] }, :status => 401 }
      # format.js   { render :js => 'alert("Hello 401")' }
      format.js   { render :template => 'errors/401.js.erb' }

    else
      ExceptionNotifier::Notifier.exception_notification(env, exception).deliver        
      format.html { render :template => "errors/500", :status => 500 } #, :layout => 'im2/application' }
      # format.js   { render :nothing => true, :status => 500 }
      format.js   { render :template => 'errors/500.js.erb' }

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