I want to log the current backtrace (stacktrace) in a Rails 3 app without an exception occurring. Any idea how?
Why do I want this? I'm trying to trace the calls that are made when Rails looks for a template so that I can choose a part of the process to override (because I want to change the view path for a particular subclassed controller of mine).
I'd like to call it from the file: gems\actionpack-3.2.3\lib\action_dispatch\middleware\templates\rescues\missing_template.erb
. I know that's not best practice, but I know it's downstream of the stack from where the search for templates occurs.
e.backtrace
. I've seen it in one of the projects I'm working with. Not the nicest approach, but it works. Hope to hear a better solution from someone else, though.
You can use 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
Output:
caller.rb:8:in `bar'
caller.rb:12:in `baz'
caller.rb:15:in `<main>'
Try using
Thread.current.backtrace
Kernel#caller
leaves out the current method. E.g. MyClass.new.returns_caller => ["(irb):42:in 'irb_binding'",...]
isn't as helpful as MyClass.new.returns_thread_backtrace => ["(irb):38:in 'backtrace'","(irb):38:in 'returns_thread_backtrace'","(irb):43:in 'irb_binding'",...]
I use this to show a custom error page when exception are raised.
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
Success story sharing
Kernel.caller
- with a dot?Kernel.new.caller
is not defined over herecaller
is an instance method. SinceKernel
module is included in every Ruby class (exceptBasicObject
in 1.9), it's available as instance method on any object (it's private, though). You can't call it asKernel.new.caller
simply because you can't instantiate a module (it doesn't havenew
method).Rails.logger.debug caller.join("\n")
orputs caller.join("\n")
. Thanks.