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.
- 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]
- Promise support[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)
- Support for custom exception attributes[link]
- Severity support[link]
- Last but not least, we follow semantic versioning 2.0.0[link]
Add the Airbrake Ruby gem to your Gemfile:
gem 'airbrake-ruby', '~> 2.2'
Invoke the following command from your terminal:
gem install airbrake-ruby
This is the minimal example that you can use to test Airbrake Ruby with your project.
require 'airbrake-ruby'
# Every Airbrake notifier must configure
# two options: `project_id` and `project_key`.
Airbrake.configure do |c|
c.project_id = 105138
c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
end
# Asynchronous error delivery.
begin
1/0
rescue ZeroDivisionError => ex
# Return value is always `nil`.
Airbrake.notify(ex)
end
puts 'A ZeroDivisionError was sent to Airbrake asynchronously!',
"Find it at your project's dashboard on https://airbrake.io"
# Synchronous error delivery.
begin
1/0
rescue ZeroDivisionError => ex
# Return value is a Hash.
response = Airbrake.notify_sync(ex)
end
puts "\nAnother ZeroDivisionError was sent to Airbrake, but this time synchronously.",
"See it at #{response['url']}"
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[:project_a].notify('Oops!', params)
# Send an exception to Project B.
Airbrake[:project_b].notify('Oops!', params)
# Wait for the notifiers to finish their work and make them inactive.
%i(project_a project_b).each { |notifier_name| Airbrake[notifier_name].close }
Before using the library and its notifiers, you must 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.
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
If your server is not able to directly reach Airbrake, you can use a built-in proxy. By default, Airbrake Ruby uses a direct connection.
Airbrake.configure do |c|
c.proxy = {
host: 'proxy.example.com',
port: 4038,
user: 'john-doe',
password: 'p4ssw0rd'
}
end
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
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
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
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
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
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
The number of seconds to wait for the connection to Airbrake to open.
Airbrake.configure do |c|
c.timeout = 10
end
Specifies which keys in the payload (parameters, session data, environment data,
etc) should be filtered. Before sending an error, filtered keys will be
substituted with the [Filtered]
label.
It accepts Strings, Symbols & Regexps, which represent keys of values to be filtered.
Airbrake.configure do |c|
c.blacklist_keys = [:email, /credit/i, 'password']
end
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]' }
If you cannot inline your keys (for example, they should be loaded from external
process), there's a way to load them later. Let's imagine Keyloader.load_keys
builds an Array of keys by talking to another process:
module Keyloader
# Builds an Array of keys (talking to another process is omitted).
def self.load_keys
[:credit_card, :telephone]
end
end
We need to wrap this call in a Proc, so the library can execute it later (it gets executed on first notify, only once):
Airbrake.configure do |c|
# You can mix inline keys and Procs.
c.blacklist_keys = [:email, proc { Keyloader.load_keys }, 'password']
end
The Proc must return an Array consisting only of the elements, which are considered to be valid for this option.
Specifies which keys in the payload (parameters, session data, environment data,
etc) 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.configure do |c|
c.whitelist_keys = [:email, /user/i, 'account_id']
end
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 }
See documentation about blacklisting using Proc objects. It's identical.
The options listed below apply to Airbrake.notify
, they do
not apply to Airbrake.notify_sync
.
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
The number of threads that handle notice sending. The default value is 1.
Airbrake.configure do |c|
c.workers = 5
end
Retrieves a configured notifier.
Airbrake[:my_notifier] #=> Airbrake::Notifier
If the notifier is not configured, returns an instance of
Airbrake::NilNotifier
(a no-op version of Airbrake::Notifier
).
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 aRuntimeException
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'
})
Accepts a block, which yields an Airbrake::Notice
:
Airbrake.notify('App crashed') do |notice|
notice[:params][:foo] = :bar
end
Returns an Airbrake::Promise
, which can be used to read Airbrake
error ids.
Severity allows categorizing how severe an error is. By
default, it's set to error
. To redefine severity, simply overwrite
context/severity
of a notice object. For example:
Airbrake.notify do |notice|
notice[:context][:severity] = 'critical'
end
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
.
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
Notices can carry custom objects attached to
the notice stash. Such notices can be produced
by build_notice
manually or provided to you by an
Airbrake integration:
# Build a notice and store a Request object in the stash.
notice = Airbrake.build_notice('oops')
notice.stash[:request] = Request.new
Airbrake.add_filter do |notice|
# Access the stored request object inside a filter and interact with it.
notice[:params][:remoteIp] = notice.stash[:request].env['REMOTE_IP']
end
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.
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)
See the block form of Airbrake.notify
for shorter syntax.
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[:my_notifier].close
end
Notifies Airbrake of a new deploy. Accepts a Hash with the following params:
Airbrake.create_deploy(
environment: 'development',
username: 'john',
repository: 'https://github.com/airbrake/airbrake-ruby',
revision: '0b77f289166c9fef4670588471b6584fbc34b0f3',
version: '1.2.3'
)
Ignores a notice. Ignored notices never reach the Airbrake dashboard. This is
useful in conjunction with Airbrake.add_filter
.
notice.ignore!
Checks whether the notice was ignored.
notice.ignored? #=> false
Accesses a notice's payload, which can be read or filtered. Payload includes:
:errors
:context
:environment
:session
:params
notice[:params][:my_param] = 'foobar'
Each notice can carry arbitrary objects stored in the notice stash, accessible
through the stash
method. Callbacks defined
via add_filter
can access the stash and attach stored
object's values to the notice payload:
notice.stash[:my_object] = Object.new
Airbrake.add_filter do |notice|
# Access :my_object from the stash and directly call its method. The return
# value will be sent to Airbrake.
notice[:params][:object_id] = notice.stash[:my_object].object_id
end
Airbrake::Promise
represents a simplified promise object (similar to promises
found in JavaScript), which allows chaining callbacks that are executed when
the promise is either resolved or rejected.
Attaches a callback to be executed when a promise is resolved (fulfilled). The promise is resolved whenever the Airbrake API successfully accepts your exception.
Yields successful response containing the id of an error at Airbrake and URL to
the error at Airbrake. Returns self
.
Airbrake.notify('Oops').then { |response| puts response }
#=> {"id"=>"00054415-8201-e9c6-65d6-fc4d231d2871",
# "url"=>"http://localhost/locate/00054415-8201-e9c6-65d6-fc4d231d2871"}
Attaches a callback to be executed when a promise is rejected. The promise is rejected whenever the API returns an error response.
Yields an error message in the form of String explaining the failure and returns
self
.
Airbrake.notify('Oops').rescue { |error| puts error }
#=> Failed to open TCP connection to localhostt:80
The library supports custom exception attributes. This is useful if you work
with custom exceptions, which define non-standard attributes and you can't
attach any additional data with help of the add_filter
API due to the fact that the data isn't available at configuration time yet.
In this case, you could define a special hook method on your exception called
#to_airbrake
. The method must return a Hash the keys of which must be a subset
of the ones mentioned in the Notice#[]
API.
class MyException
def initialize
@http_code = 404
end
# The library expects you to define this method. You must return a Hash,
# containing the keys you want to modify.
def to_airbrake
{ params: { http_code: @http_code } }
end
end
# The `{ http_code: 404 }` Hash will transported to the Airbrake dashboard via
# the `#to_airbrake` method.
Airbrake.notify(MyException.new)
Note: you don't have to call Airbrake.notify
manually to be able to benefit
from this API. It should "just work".
The maximum size of an exception is 64KB. Exceptions that exceed this limit will be truncated to fit the size.
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
Critical exceptions are unhandled exceptions that terminate your program. By default, the library doesn't report them. However, you can either depend on the airbrake gem instead, which supports them, or you can add the following code somewhere in your app:
at_exit do
Airbrake.notify_sync($!) if $!
end
- CRuby >= 2.0.0
- JRuby >= 9k
- Rubinius >= 2.2.10
In case you have a problem, question or a bug report, feel free to:
- file an issue
- send us an email
- tweet at us
- chat with us (visit airbrake.io and click on the round orange button in the bottom right corner)
The project uses the MIT License. See LICENSE.md for details.