WatCatcher

TODO: Write a gem description

Installation

Add this line to your application's Gemfile:

gem 'wat_catcher'

And then execute:

$ bundle

Or install it yourself as:

$ gem install wat_catcher

Usage

Configuration

You can configure the wat_catcher in 2 ways; 1) via a config/wat_catcher.yml file or in ruby.

Currently there are only 2 configuration options: host: This is the beginning of the url used to post wats to wattle. It should look something like "https://yourwattleserver.com". disabled: If truthy this will stop any wats from being posted.

Here are 2 identical configs specified in the yml and in ruby.

config/wat_catcher.yml

production: &default
  host: "https://wattle.yourhost.com"

development:
  <<: *default
  disabled: true

test:
  <<: *default
  disabled: true

OR

config/application.rb

module YourApp
  class Application < Rails::Application
    WatCatcher.configuration.host =  "https://wattle.yourhost.com"
  end
end

config/environments/development.rb

YourApp::Application.configure do
  WatCatcher.configuration.disabled = true
end

config/environments/test.rb

YourApp::Application.configure do
  WatCatcher.configuration.disabled = true
end

Adding Telemetry

In config/wat_catcher.yml:

production: &default
  statsd_host: statsd.service.consul
  statsd_port: 9125
  metrics_disabled: false # defaults to true

Alternatively, this can be configured in config/application.rb or environment file (e.g. config/environments/production.rb).

module YourApp
  class Application < Rails::Application
    WatCatcher.configuration.statsd_host = "statsd.service.consul"
    WatCatcher.configuration.statsd_port = 9125
    WatCatcher.configuration.metrics_disabled = false
  end
end
YourApp::Application.configure do
  WatCatcher.configuration.metrics_disabled = false
end

Mount the engine in your app for javascript errors

To get around cross-origin issues, an engine was created that accepts POSTs of client exceptions and puts a sidekiq job in to post the wat to wattle.

In your routes.rb:

YourApp::Application.routes.draw do
  mount WatCatcher::Engine => '/wat_catcher'
end

Integrating with a controller

Posting errors from a controller action is done by simply including the CatcherOfWats concern into your controller

class ApplicationController < ActionController::Base
  include WatCatcher::CatcherOfWats
end

That will install an around_filter that reports and re-raises anything raised in an action.

If you want to record some info about what user saw the error simply implement a 'wat_user' method on the controller

class ApplicationController < ActionController::Base

  def wat_user
    {id: logged_in? ? "account_#{current_user.id}" : nil }
  end

end

The wat_user will be turned into a json object. You may put any field in the wat_user, but the 'id' field will be used by wattle to decide how many unique users have seen an exception.

Integrating with sidekiq

To have sidekiq post exceptions from sidekiq jobs you must install the sidekiq middleware:

::Sidekiq.configure_server do |config|
  config.server_middleware do |chain|
    chain.add ::WatCatcher::SidekiqMiddleware
  end
end

If you want to some info about what user saw the error you need to implement a 'wat_user' method on the worker. The user object returned by this wat_user follows the same rules as the wat_user on a controller, but the way it's called is more complicated.

Whatever method is being called by sidekiq to start the job, make sure it implements a wat_user method that accepts the same arguments.

Here are some ways that a wat_user method could be implemented:

class SomeModel < ActiveRecord::Base
  belongs_to :account
  class << self
    def notify(some_model_id)
      SomeModel.find(some_model_id).some_delayed_method
    end

    def wat_user(some_model_id)
    { id: "some_model_#{some_model_id}" }
    end
  end


  def wat_user(*args)
    { id: "some_model_#{id}" }
  end

  def some_delayed_method
    raise 'herp'
  end

  def some_other_delayed_method(an_arg)
    raise 'derp'
  end

end

# Queuing on SomeModel like the following should generate a wat_user with a reasonable id.
SomeModel.last.delay.some_delayed_method
SomeModel.last.delay.some_other_delayed_method('blarg')
SomeModel.delay.notify(12)


class SomeWorker
  include Sidekiq::Worker

  def perform(some_arg)
    raise "wat? #{some_arg}"
  end

  def wat_user(some_arg)
    { id: "SomeWorker: #{some_arg}" }
  end
end

# The queued job will raise an error and register a wat with the user "SomeWorker: derp"
SomeWorker.perform_async("derp")

When in doubt, check out the cconstantine/wattle. It uses itself to report errors and uses all of the above features.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request