/airbrake-ruby

A plain Ruby Airbrake notifier

Primary LanguageRubyMIT LicenseMIT

Airbrake Ruby

Build Status semver Documentation Status Issue Stats Issue Stats

Airbrake Ruby

Introduction

Airbrake Ruby is a plain Ruby notifier for Airbrake, the leading exception reporting service. Airbrake Ruby provides minimalist API that enables the ability to send any Ruby exception to the Airbrake dashboard. The library is extremely lightweight, contains no dependencies and perfectly suits plain Ruby applications. For apps that are built with Rails, Sinatra or any other Rack-compliant web framework we offer the airbrake gem. It has additional features such as reporting of any unhandled exceptions automatically, integrations with Resque, Sidekiq, Delayed Job and many more.

Key features

  • Uses the new Airbrake JSON API (v3)[link]
  • Simple, consistent and easy-to-use library API[link]
  • Awesome performance (check out our benchmarks)[link]
  • Asynchronous exception reporting[link]
  • Flexible logging support (configure your own logger)[link]
  • Flexible configuration options (configure as many Airbrake notifers in one application as you want)[link]
  • Support for proxying[link]
  • Support for environments[link]
  • Filters support (filter out sensitive or unwanted data that shouldn't be sent)[link]
  • Ability to ignore exceptions based on their class, backtrace or any other condition[link]
  • Support for Java exceptions occurring in JRuby
  • SSL support (all communication with Airbrake is encrypted by default)
  • Support for fatal exceptions (the ones that terminate your program)
  • Last but not least, we follow semantic versioning 2.0.0[link]

Installation

Bundler

Add the Airbrake Ruby gem to your Gemfile:

gem 'airbrake-ruby', '~> 1.1'

Manual

Invoke the following command from your terminal:

gem install airbrake-ruby

Examples

Basic example

This is the minimal example that you can use to test Airbrake Ruby with your project.

require 'airbrake-ruby'

Airbrake.configure do |c|
  c.project_id = 105138
  c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end

begin
  1/0
rescue ZeroDivisionError => ex
  Airbrake.notify(ex)
end

puts 'Check your dashboard on http://airbrake.io'

Creating a named notifier

A named notifier can co-exist with the default notifier. You can have as many notifiers configured differently as you want.

require 'airbrake-ruby'

# Configure first notifier for Project A.
Airbrake.configure(:project_a) do |c|
  c.project_id = 105138
  c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end

# Configure second notifier for Project B.
Airbrake.configure(:project_b) do |c|
  c.project_id = 123
  c.project_key = '321'
end

params = { time: Time.now }

# Send an exception to Project A.
Airbrake.notify('Oops!', params, :project_a)

# Send an exception to Project B.
Airbrake.notify('Oops!', params, :project_b)

Configuration

Before using the library and its notifiers, you must to configure them. In most cases, it is sufficient to configure only one, default, notifier.

Airbrake.configure do |c|
  c.project_id = 105138
  c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end

Many notifiers can co-exist at the same time. To configure a new notifier, simply provide an argument for the configure method.

Airbrake.configure(:my_notifier) do |c|
  c.project_id = 105138
  c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end

You cannot reconfigure already configured notifiers.

Config options

project_id & project_key

You must set both project_id & project_key.

To find your project_id and project_key navigate to your project's General Settings and copy the values from the right sidebar.

Airbrake.configure do |c|
  c.project_id = 105138
  c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end

proxy

If your server is not able to directly reach Airbrake, you can use built-in proxy. By default, Airbrake Ruby uses direct connection.

Airbrake.configure do |c|
  c.proxy = {
    host: 'proxy.example.com',
    port: 4038,
    user: 'john-doe',
    password: 'p4ssw0rd'
  }
end

logger

By default, Airbrake Ruby outputs to STDOUT. The default logger level is Logger::WARN. It's possible to add your custom logger.

Airbrake.configure do |c|
  c.logger = Logger.new('log.txt')
end

app_version

The version of your application that you can pass to differentiate exceptions between multiple versions. It's not set by default.

Airbrake.configure do |c|
  c.app_version = '1.0.0'
end

host

By default, it is set to airbrake.io. A host is a web address containing a scheme ("http" or "https"), a host and a port. You can omit the port (80 will be assumed) and the scheme ("https" will be assumed).

Airbrake.configure do |c|
  c.host = 'http://localhost:8080'
end

root_directory

Configures the root directory of your project. Expects a String or a Pathname, which represents the path to your project. Providing this option helps us to filter out repetitive data from backtrace frames and link to GitHub files from our dashboard.

Airbrake.configure do |c|
  c.root_directory = '/var/www/project'
end

environment

Configures the environment the application is running in. Helps the Airbrake dashboard to distinguish between exceptions occurring in different environments. By default, it's not set.

Airbrake.configure do |c|
  c.environment = :production
end

ignore_environments

Setting this option allows Airbrake to filter exceptions occurring in unwanted environments such as :test. By default, it is equal to an empty Array, which means Airbrake Ruby sends exceptions occurring in all environments.

Airbrake.configure do |c|
  c.ignore_environments = [:test]
end

timeout

The number of seconds to wait for the connection to Airbrake to open.

Airbrake.configure do |c|
  c.timeout = 10
end

Asynchronous Airbrake options

The options listed below apply to Airbrake.notify, they do not apply to Airbrake.notify_sync.

queue_size

The size of the notice queue. The default value is 100. You can increase the value according to your needs.

Airbrake.configure do |c|
  c.queue_size = 200
end

workers

The number of threads that handle notice sending. The default value is 1.

Airbrake.configure do |c|
  c.workers = 5
end

API

Airbrake

Airbrake.notify

Sends an exception to Airbrake asynchronously.

Airbrake.notify('App crashed!')

As the first parameter, accepts:

  • an Exception (will be sent directly)
  • any object that can be converted to String with #to_s (the information from the object will be used as the message of a RuntimeException that we build internally)
  • an Airbrake::Notice

As the second parameter, accepts a hash with additional data. That data will be displayed in the Params tab in your project's dashboard.

Airbrake.notify('App crashed!', {
  anything: 'you',
  wish: 'to add'
})

Airbrake.notify_sync

Sends an exception to Airbrake synchronously. Returns a Hash with an error ID and a URL to the error.

Airbrake.notify_sync('App crashed!')
#=> {"id"=>"1516018011377823762", "url"=>"https://airbrake.io/locate/1516018011377823762"}

Accepts the same parameters as Airbrake.notify.

Airbrake.add_filter

Runs a callback before .notify kicks in. Yields an Airbrake::Notice. This is useful if you want to ignore specific notices or filter the data the notice contains.

If you want to ignore a notice, simply mark it with Notice#ignore!. This interrupts the execution chain of the add_filter callbacks. Once you ignore a notice, there's no way to unignore it.

This example demonstrates how to ignore all notices.

Airbrake.add_filter(&:ignore!)

Instead, you can ignore notices based on some condition.

Airbrake.add_filter do |notice|
  if notice[:errors].any? { |error| error[:type] == 'StandardError' }
    notice.ignore!
  end
end

In order to filter a notice, simply change the data you are interested in.

Airbrake.add_filter do |notice|
  if notice[:params][:password]
    # Filter out password.
    notice[:params][:password] = '[Filtered]'
  end
end
Using classes for building filters

For more complex filters you can use the special API. Simply pass an object that responds to the #call method.

class MyFilter
  def call(notice)
    # ...
  end
end

Airbrake.add_filter(MyFilter.new)

The library provides two default filters that you can use to filter notices: KeysBlacklist & KeysWhitelist.

The KeysBlacklist filter

The KeysBlacklist filter filters specific keys (parameters, session data, environment data). Before sending the notice, filtered keys will be substituted with the [Filtered] label.

It accepts Strings, Symbols & Regexps, which represent keys to be filtered.

Airbrake.blacklist_keys([:email, /credit/i, 'password'])
Airbrake.notify('App crashed!', {
  user: 'John',
  password: 's3kr3t',
  email: 'john@example.com',
  credit_card: '5555555555554444'
})

# The dashboard will display this parameter as filtered, but other values won't
# be affected:
#   { user: 'John',
#     password: '[Filtered]',
#     email: '[Filtered]',
#     credit_card: '[Filtered]' }
The KeysWhitelist filter

The KeysWhitelist filter allows you to specify which keys should not be filtered. All other keys will be substituted with the [Filtered] label.

It accepts Strings, Symbols & Regexps, which represent keys the values of which shouldn't be filtered.

Airbrake.whitelist([:email, /user/i, 'account_id'])
Airbrake.notify(StandardError.new('App crashed!'), {
  user: 'John',
  password: 's3kr3t',
  email: 'john@example.com',
  account_id: 42
})

# The dashboard will display this parameter as is, but all other values will be
# filtered:
#   { user: 'John',
#     password: '[Filtered]',
#     email: 'john@example.com',
#     account_id: 42 }

Airbrake.build_notice

Builds an Airbrake notice. This is useful, if you want to add or modify a value only for a specific notice. When you're done modifying the notice, send it with Airbrake.notify or Airbrake.notify_sync.

notice = Airbrake.build_notice('App crashed!')
notice[:params][:username] = user.name
airbrake.notify_sync(notice)

Airbrake.close

Makes the notifier a no-op, which means you cannot use the .notify and .notify_sync methods anymore. It also stops the notifier's worker threads.

Airbrake.close
Airbrake.notify('App crashed!') #=> raises Airbrake::Error

If you want to guarantee delivery of all unsent exceptions on program exit, make sure to close your Airbrake notifier. Usually, this can be done with help of Ruby's at_exit hook.

at_exit do
  # Closes the default notifier.
  Airbrake.close

  # Closes a named notifier.
  Airbrake.close(:my_notifier)
end

Notice

Notice#ignore!

Ignores a notice. Ignored notices never reach the Airbrake dashboard. This is useful in conjunction with Airbrake.add_filter.

notice.ignore!

Notice#ignored?

Checks whether the notice was ignored.

notice.ignored? #=> false

Notice#[] & Notice#[]=

Accesses a notice's modifiable payload, which can be read or filtered. Modifiable payload includes:

  • :errors
  • :context
  • :environment
  • :session
  • :params
notice[:params][:my_param] = 'foobar'

Additional notes

Exception limit

The maximum size of an exception is 64KB. Exceptions that exceed this limit will be truncated to fit the size.

Running benchmarks

To run benchmarks related to asynchronous delivery, make sure to start a web server on port 8080. We provide a simple server, which can be started with this command (you need to have the Go programming language installed):

go run benchmarks/server.go

In order to run benchmarks against master, add the lib directory to your LOAD_PATH and choose the benchmark you are interested in:

ruby -Ilib benchmarks/notify_async_vs_sync.rb

Supported Rubies

  • CRuby >= 1.9.2
  • JRuby >= 1.9-mode
  • Rubinius >= 2.2.10

Contact

In case you have a problem, question or a bug report, feel free to:

License

The project uses the MIT License. See LICENSE.md for details.