例外を発生させずにRubyで現在のスタックトレースを取得する


138

現在のバックトレース(スタックトレース)を例外なしで Rails 3アプリに記録したいのですが。どのように考えていますか?

なぜこれが必要なのですか?オーバーライドするプロセスの一部を選択できるように、Railsがテンプレートを検索するときに行われる呼び出しを追跡しようとしています(特定のサブクラス化されたコントローラーのビューパスを変更したいためです)。

次のファイルから呼び出します:gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb。私はそれがベストプラクティスではないことを知っていますが、テンプレートの検索が行われるスタックの下流にあることを知っています。


4
汚い解決策:そこで例外を発生させ、すぐに救済してログに記録しますe.backtrace。私が取り組んでいるプロジェクトの1つでそれを見たことがあります。最も良い方法ではありませんが、うまくいきます。しかし、他の誰かからより良い解決策を聞くことを願っています。
KL-7

回答:


185

使用できます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 2013

8
いいえ、技術的にcallerはインスタンスメソッドです。KernelモジュールはすべてのRubyクラスに含まれているため(BasicObject1.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、2015年

20

使ってみてください

Thread.current.backtrace

1
この答えの利点は、現在のメソッドがバックトレースに含まれているに対し、現在のメソッドは省略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.