Automatically Logging Exceptions in Ruby
If you want to take a walk on the wild side, try this:
class Exception
alias real_init initialize
def initialize(*args)
real_init *args
# log the error (self) or its args here
end
end
This will intercept the creation of new exception objects at the moment of creation. How to log exceptions automatically in Rails?
I ended up using rescue_from
in the ApplicationController
, logging the exception message and backtrace, and then using params[:controller]
and params[:action]
to determine what controller/action to redirect to.
For example, if PostsController#show
exception'ed out, I would redirect to PostsController#index
from within rescue_from
. It's been working so far, so it doesn't seem to be a bad thing to do redirect_to
from within rescue_from
. Time will let me know, I'm sure! (Just need to make sure that my redirects don't cause some infinite loops!)
And just in someone is interested in this hack (try at your own risk!):
class ApplicationController < ActionController::Base
def determine_redirect_to_path(controller,action)
...
end
rescue_from StandardError do |exception|
backtrace_size = exception.backtrace.size
if backtrace_size >= 2 then max_range = 2
elsif backtrace_size >= 1 then max_range = 1
end
if max_range > 0
s = "rescued_from:: #{params[:controller]}##{params[:action]}: #{exception.inspect}\n#{exception.backtrace[0..max_range].to_s}\n"
logger.error s
end
redirect_to determine_redirect_to_path(params[:controller],params[:action])
end
end
Ruby: where does ruby log its errors (location of errors / exceptions)?
There are no log files. When errors occur, the Ruby standard library will write its messages to the standard error stream. You can redirect this to a file if you'd like.
Of course, you can do whatever you want in your own code. It's absolutely possible to open a file and log messages to it. There are many logging libraries that provide this functionality.
How can I log Rails errors into a separate log file?
For example, to log all ActiveRecord::Base errors in a file called log/exceptions.log
new_logger = Logger.new('log/exceptions.log')
new_logger.level = Logger::ERROR
new_logger.error('THIS IS A NEW EXCEPTION!')
ActiveRecord::Base.logger = new_logger
For controllers and view(because ActionView logger doesn't have it's own logger, so it depends on the ActionController logger):ActionController::Base.logger = new_logger
Ruby on Rails 3.1 - Logging exception in the database
For seemingly outdated gems such as exception_logger
, I find it helpful to check out other users' forks of the gem using GitHub's network feature. You'll usually find that someone has updated or continued to maintain the gem even though the original author has not. For example, the network for exception_logger
is quite active, especially this particular fork by QuBiT.
Check out The Ruby Toolbox - Exception Notification for a list of widely used "exception notification" tools. Unfortunately most of them are a bit outdated, but the technique described above for finding more active forks applies as well.
If you aren't opposed to a paid solution, Airbrake and Exceptional both work well (although Airbrake's new pricing structure make them quite prohibitive for a small project; Exceptional is reasonably priced).
Unhandled Exceptions in Ruby
Ruby doesn't have generic handlers, but instead you wrap the code which might generate exceptions. For example:
begin
# ... Do stuff
rescue => e
$stderr.puts("[%s] %s" % [ e.class, e ])
$stderr.puts(e.backtrace.join("\n"))
end
Where that rescues all standard exceptions and displays some diagnostic output. You can do whatever you want in the rescue
block. Any uncaught exceptions will bubble up to your top-level automatically.This must be the top-level code for your Ruby application.
The closest thing to what you're talking about in Ruby is the at_exit
handler you can define, but this runs in every exit scenario, not just uncaught exceptions.
Why is it bad style to `rescue Exception = e` in Ruby?
TL;DR: Use StandardError
instead for general exception catching. When the original exception is re-raised (e.g. when rescuing to log the exception only), rescuing Exception
is probably okay.
Exception
is the root of Ruby's exception hierarchy, so when you rescue Exception
you rescue from everything, including subclasses such as SyntaxError
, LoadError
, and Interrupt
.Rescuing Interrupt
prevents the user from using CTRLC to exit the program.
Rescuing SignalException
prevents the program from responding correctly to signals. It will be unkillable except by kill -9
.
Rescuing SyntaxError
means that eval
s that fail will do so silently.
All of these can be shown by running this program, and trying to CTRLC or kill
it:
loop do
begin
sleep 1
eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
rescue Exception
puts "I refuse to fail or be stopped!"
end
end
Rescuing from Exception
isn't even the default. Doingbegin
# iceberg!
rescue
# lifeboats
end
does not rescue from Exception
, it rescues from StandardError
. You should generally specify something more specific than the default StandardError
, but rescuing from Exception
broadens the scope rather than narrowing it, and can have catastrophic results and make bug-hunting extremely difficult.If you have a situation where you do want to rescue from
StandardError
and you need a variable with the exception, you can use this form:begin
# iceberg!
rescue => e
# lifeboats
end
which is equivalent to:begin
# iceberg!
rescue StandardError => e
# lifeboats
end
One of the few common cases where it’s sane to rescue from
Exception
is for logging/reporting purposes, in which case you should immediately re-raise the exception:begin
# iceberg?
rescue Exception => e
# do some logging
raise # not enough lifeboats ;)
end
Related Topics
How to Resize Image Only If Width Exceeds with Graphics/Image Magick
Access Rake Task Description from Within Task
What Is Ruby's Stringio Class Really
Adding Two Activerecord::Relation Objects
Using Ruby with Mechanize to Log into a Website
How to Print a Multi-Dimensional Array in Ruby
Ruby 2.0 Bytecode Export/Import
What Hash Function Does Ruby Use
Why Can't The Mail Block See My Variable
How to Remove a Url's Trailing Slash in a Rails App? (In a Seo View)
How to Fix a Deadlock in Join() in Ruby
In Ruby, Is Truthiness Idiomatic for a Method Name Ending with a Question Mark
Thor Executable - Ignore Task Name
How to Reference a Local Gem from a Ruby Script
What's The Best Way to Extract Excel Cell Comments Using Perl or Ruby