To keep track of any exceptions in our applications, we needed an easy way of being notified when an error occurred. We initially looked at the exception notifier plugin but whilst it did what it said on the tin, receiving an email for each exception was too noisy and distracting.
Instead, we decided to build upon our existing Beanstalkd queue setup and using our beanstalk messaging plugin we were able to put together a simple Rails plugin that forwards exceptions to a beanstalkd queue instance. This allowed us to decouple the collection of exceptions from processing them and deal with them in whichever way we liked.
Installing the plugin
This plugin requires the beanstalk messaging plugin. Once you’ve installed this, you can install the exception messaging plugin.
$ ./script/plugin install http://svn.reevoo.com/repos/plugins/exception_messaging/
Configuration
The plugin provides a class-level method that allows you to specify the queue that you want exceptions to be sent to. Assuming we have access to an instance of a Beanstalk::QueueManager, qm, we can tell our app to forward all exceptions to an “exceptions” queue by adding the following line to our application controller:
class ApplicationController < ActionController::Base
notifies_exceptions_to qm.queue(:exceptions)
end
Ideas for processing exceptions
The simplest thing that you can do is write a small Ruby script that takes each exception and emails it, just like the exception notification plugin. If you would rather not send an email for each exception, you could batch email exceptions instead. The following example uses code from the beanstalk messaging plugin:
## exception_mailer.rb
class ExceptionMailer < ActionMailer::Base
def batch_exception_notification(exceptions, recipient)
recipients recipient
from "sysadmin@yoursite.com"
subject "Application exceptions"
body :exceptions => exceptions
end
end
## batch_exception_notification.erb
<% @exceptions.each do |exception| %>
<%= exception %>
<% end %>
## process_exceptions.rb
queue_manager = Beanstalk::QueueManager.new('path/to/my/beanstalk/config.yml')
queue_poller = Beanstalk::QueuePoller.new(queue_manager)
# collect exceptions and email each 100 in a batch
queue_poller.poll_with_buffer(:exceptions, 100) do |messages|
exceptions = messages.map(&:ybody)
ExceptionMailer.deliver_batch_exception_notification(exceptions, 'sysadmin@yoursite.com')
messages.each { |m| m.delete }
end
Alternatively, you could write a basic Rails/Merb exception reporting application and write a simple Rake task to grab the latest applications and insert them into the application database, which could be run periodically via a cron job.
Also see: Collecting exceptions asynchronously using Beanstalkd and Hoptoad.
