This client library reports exceptions to Squash, the Squarish exception reporting and management system.
Comprehensive documentation is written in YARD- and Markdown-formatted comments
throughout the source. To view this documentation as an HTML site, run
rake doc
.
For an overview of the various components of Squash, see the website documentation at https://github.com/SquareSquash/web.
This library is compatible with Ruby 1.9.2 and later, including JRuby.
The only dependency is the json
gem (https://rubygems.org/gems/json). You can use
any JSON gem that conforms to the typical standard (require 'json'; object.to_json
).
Add the Squash client to your Gemfile with
gem 'squash_ruby'
. Before you can use Squash, you must configure it (see
Configuration below). At a minimum, you must specify the API host and which
project you are recording exceptions for:
Squash::Ruby.configure api_key: 'YOUR_API_KEY',
api_host: 'https://your.squash.host',
environment: 'production'
To use Squash to manage your exceptions, place a begin::rescue
statement at
the highest level of your code. Inside the rescue
block, make a call to
{Squash::Ruby.notify} with the exception. In general, you probably want to
rescue all subclasses of Object
, so you catch every possible exception.
Example:
begin
all_of_your_code
rescue Object => err
Squash::Ruby.notify err
raise
end
In this example the exception is re-raised to take advantage of Ruby's typical last-resort exception handling as well.
There are many additional features you can take advantage of; see Additional Features below.
There are a number of other features you can take advantage of to help you debug your exceptions:
Exceptions can be annotated with freeform user data. This data can take any
format and have any meaning, typically being relevant to the exception at hand.
This is in fact the system that squash_rails
uses to annotate an exception
with information about the Rails request.
There are multiple ways to add user data to an exception. By default, user data
is culled from any instance variables set in the exception. This means that for
those exceptions that store additional information in instance variables, you
get user data "for free." An example is the ActiveRecord::RecordInvalid
exception, which stores the invalid record as an instance variable.
You can also add user data using the {Squash::Ruby.add_user_data} method:
input = gets
Squash::Ruby.add_user_data(input: input) do
process_input # may raise an exception
end
And lastly, if you require squash/ruby/exception_additions
, you can add user
data directly in the exception constructor:
require 'squash/ruby/exception_additions'
def process_value(value)
raise ArgumentError.new("value must be a number", value: value) unless value.kind_of?(Fixnum)
# [...]
end
Requiring that file also lets you add user data to exceptions you catch and re-raise:
require 'squash/ruby/exception_additions'
begin
do_something_with_input(input)
rescue ArgumentError => err
err.user_data input: input
raise # assumed that Squash::Ruby.notify is called somewhere further up in the stack
end
If monkey-patching doesn't appeal to you, then don't load
squash/ruby/exception_additions
; it's not required for the client to work.
You can ignore certain exceptions within a block of code if those exceptions are not worth sending to Squash. Use the {Squash::Ruby.ignore_exceptions} method:
Squash::Ruby.ignore_exceptions(SocketError, Net::HTTPError) do
some_http_code_that_could_fail
end
The exceptions will be raised (not eaten) but will not be reported to Squash.
You can also globally ignore exceptions using the ignored_exceptions
configuration; see Configuration below.
You can configure the client with the {Squash::Ruby.configure} method. Calling this method multiple times will merge new values in with the existing configuration. The method takes a hash, which accepts the following (symbol) keys:
disabled
: Iftrue
, the Squash client will not report any errors.api_key
: The API key of the project that exceptions will be associated with. This configuration option is required. The value can be found by going to the project's home page on Squash.environment
: The environment that exceptions will be associated with.project_root
: The path to your project's root directory. This path will be stripped from backtrace lines. By default it's set to the working directory.mirrored_repository
: Set this option to be true if your repository root is a mirrored Git repository.exception_behavior_when_disabled
: Set this option to customize Squash's behavior when an exception is raised in an environment where Squash is disabled (typically development and test). Values areignore
(default): exception is ignored;raise
: exception is raised; andlog
: exception is logged at the error level to the failsafe log.
Squash can determine the current code revision using one of two methods. Specify only one of the following configuration keys:
revision_file
: The path to a file storing the SHA1 of the current Git revision. This is the revision of the code that is currently running.revision
: The 40-character SHA1 of the current deployed revision.repository_root
: The path to the working directory of the Git repository that is currently running. Use this option if your deployed code is a working Git repository.
By default, repository_root
is assumed and is set to Dir.getwd
. Other
options override repository_root
.
api_host
: The host on which Squash is running. This field is required.notify_path
: The path to post new exception notifications to. By default it's set to/api/1.0/notify
.transmit_timeout
: The amount of time to wait before giving up on trasmitting an error. By default this is treated as both an open and a read timeout.max_variable_size
: The maximum size (in bytes) of a serialized representation of a value that will be transmitted over the network. Values that serialize to larger than this size will be replaced with a placeholder.timeout_protection
: aproc { |timeout, &block| ... }
that runs the given block, and times out aftertimeout
seconds. By default this will useSystemTimer
if present, or else the built inTimeout
class, but can be overridden to provide more fine grain logic around timeouts.
ignored_exception_classes
: An array of exception class names that will not be reported to Squash.ignored_exception_messages
: A hash mapping an exception class name to an array of regexes. Exceptions of that class whose messages match a regex in the list will not be reported to Squash.ignored_exception_procs
: An array ofProc
objects that can be used to filter exceptions. Takes as arguments 1) the exception and 2) the user data hash. Should returntrue
if the exception should be ignored (not reported) and false otherwise. The user data hash can include stuff useful to extended client libraries (e.g., Squash Rails client); an example:
Squash::Ruby.configure ignored_exception_procs: lambda do |exception, user_data|
exception.kind_of?(ActiveRecord::RecordNotFound) && user_data[:headers]['X-Testing'].blank?
end
failsafe_log
: The pathname of a log file where failsafe exceptions will be recorded (see Failsafe Reporting below). By default, records to a file namedsquash.failsafe.log
in the current working directory.disable_failsafe
: Iftrue
, the failsafe handler will be disabled. Exceptions raised when Squash is processing another exception will be handled normally by the Ruby interpreter.
Exceptions are transmitted to Squash using JSON-over-HTTPS. A default API endpoint is pre-configured, though you can always set your own (see Configuration above).
By default, Net::HTTP
is used to transmit errors to the API server. If you
would prefer to use your own HTTP library, you can override the
{Squash::Ruby.http_transmit} method. This method is also used for deploy
notification.
In the event that the Squash client itself raises an exception when processing
an exception, it will log that exception to the failsafe log. (See the
failsafe_log
configuration option, described above.) Both the original
exception and the failsafe error will be logged. The original exception will
still be re-raised, but the failsafe error will be "eaten."
If for some reason the exceptions cannot be logged (e.g., a permissions error), they will be logged to standard error.
It would behoove the engineers of a project using Squash to periodically check the failsafe log, as it may contain exceptions that couldn't be reported due to, e.g., bugs in generating user data.