Dapatkan pelacakan tumpukan saat ini di Ruby tanpa memunculkan pengecualian

141

Saya ingin mencatat lacak balik saat ini (stacktrace) di aplikasi Rails 3 tanpa terjadi pengecualian. Tahu bagaimana caranya?

Mengapa saya menginginkan ini? Saya mencoba melacak panggilan yang dibuat saat Rails mencari templat sehingga saya dapat memilih bagian dari proses untuk diganti (karena saya ingin mengubah jalur tampilan untuk pengontrol subclass tertentu milik saya).

Saya ingin menyebutnya dari file: gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb. Saya tahu itu bukan praktik terbaik, tetapi saya tahu ini adalah hilir tumpukan dari mana pencarian template terjadi.

JellicleCat
sumber
4
Solusi kotor: buat pengecualian di sana, segera selamatkan dan catat e.backtrace. Saya telah melihatnya di salah satu proyek yang saya kerjakan. Bukan pendekatan terbaik, tapi berhasil. Berharap untuk mendengar solusi yang lebih baik dari orang lain.
KL-7

Jawaban:

186

Anda dapat menggunakan 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

Keluaran:

caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'
KL-7
sumber
Bukankah Kernel.caller- dengan sebuah titik? Kernel.new.callertidak ditentukan di sini
ekologi
8
Tidak, secara teknis calleradalah metode contoh. Karena Kernelmodul disertakan dalam setiap kelas Ruby (kecuali BasicObjectdi 1.9), itu tersedia sebagai metode instance pada objek apa pun (meskipun itu bersifat pribadi). Anda tidak dapat menyebutnya Kernel.new.callersesederhana karena Anda tidak dapat membuat instance modul (tidak memiliki newmetode).
KL-7
yang satu ini mendukung parameter untuk melewati sejumlah penelepon; lihat: stackoverflow.com/a/3829269/520567
akostadinov
7
Untuk penggunaan cetak cantik - Rails.logger.debug caller.join("\n")atau puts caller.join("\n"). Terima kasih.
Jignesh Gohel
20

Coba gunakan

Thread.current.backtrace
Rajat Bansal
sumber
1
Keuntungan dari jawaban ini adalah bahwa ia menyertakan metode saat ini di lacak balik, sedangkan Kernel#callermengabaikan metode saat ini. Misalnya MyClass.new.returns_caller => ["(irb):42:in 'irb_binding'",...] tidak membantu seperti MyClass.new.returns_thread_backtrace => ["(irb):38:in 'backtrace'","(irb):38:in 'returns_thread_backtrace'","(irb):43:in 'irb_binding'",...]
stwr667
6

Saya menggunakan ini untuk menampilkan halaman kesalahan kustom ketika pengecualian dimunculkan.

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
Stefano Lampis
sumber