Wednesday, July 17, 2013

Fast exception notification in rails

There are several highly regarded hosted exception notification and paging services services for rails apps such as Exceptional, AirbrakeBugsnag, PagerDuty but all of those cost $10-30/mo and with the exception of Bugsnag none of them have a free tier (note all of them have free trials).  So if you're starting a new web app and you intend to operate it like a pro, i.e. you want to be woken up in the middle of the night when something goes wrong you've got some work to do...  But it's not very much.  In this post you'll see how to integrate Amazon's Simple Notification service with the exception_notification gem.

Assumptions:

  1. You've got a Rails 3 app...
  2. Running on AWS...
  3. And you have a mobile phone that supports text messages
First install and setup the exception_notification gem as documented on their github page.  In a nutshell.  Add "gem 'exception_notification'" to your Gemfile and run "bundle install"

Next lets setup a new Simple Notification Service topic and subscribe our mobile phone to it (full SNS documentation).

Create the topic:

Topic details without a subscription:

Create a subscription for our mobile phone:

A confirmation is bounced to our phone:

Confirm from our phone:


Topic and subscription are setup and ready to use:
Next you should grab the aws-sdk for Ruby and follow the installation instructions.  In a nutshell...  A "gem 'aws-sdk'" to your Gemfile.  Run "bundle install".  Create an aws.yml with your access key ID, and secret access key.  Create an initializer that pulls the aws.yml in to your app and sets up various AWS clients.  Assuming you've done that lets create our SNS notifier and configure our app to use it on exceptions.

In config/environments/production.rb add this code:
  config.middleware.use ExceptionNotification::Rack, :sns => {:topic_name => 'test-topic'}

Create lib/exception_notifier/sns_notifier.rb:

module ExceptionNotifier
  class SnsNotifier   
    attr_accessor :topic
    def initialize(options)
      begin
        @topic = SNS_CLIENT.topics.detect {|t| t.name == options[:topic_name]}
      rescue                                                                                    
      end
    end
    def call(exception, options={})
      @topic.publish("#{exception.class.name}: '#{exception.message}' at '#{exception.backtrace.first}'") if active?
    end
    private
    def active?
      !@topic.nil?
    end
  end
end
That's it.  Except of course to add an exception into your app and watch the notification on your phone:

 
 

No comments:

Post a Comment