Giter VIP home page Giter VIP logo

yeti_exception's Introduction

yeti_exception

Enhanced exceptions with a details hash and more

Installation

Add this line to your application's Gemfile:

gem 'yeti_exception'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install yeti_exception

Usage

The YetiException::Error class

YetiException::Error is a subclass of StandardError that adds some extra attributes:

  • The class in which the exception was raised

  • A Hash of arbitrary details about the exception

  • A transient boolean flag

  • An HTTP response status

The exception's #message is constructed as a string of key=value pairs from the details hash.

ex = YetiException::Error.new(self,                                 # class
                              { some: 'details', more: 'stuff' },   # details hash
                              false,                                # transient
                              400)                                  # HTTP status

ex.message #=> "some=\"details\" more=\"stuff\""

Default values for transient and http_status will be used if not provided.

ex = YetiException::Error.new(self, { some: 'details', more: 'stuff' })

ex.transient #=> true
ex.http_status #=> 500

Subclasses and customization

YetiException::Error has some simple included subclasses for convenience.

YetiException::FinalError is a non-transient error. Its default HTTP status is 500.

ex = YetiException::FinalError.new(self, { some: 'details', more: 'stuff' }, 503)

ex.transient #=> false

ex = YetiException::FinalError.new(self, { some: 'details', more: 'stuff' })

ex.http_status #=> 500

YetiException::ClientError is similar. It is intended to represent an invalid HTTP request, so its default HTTP status is 400.

ex = YetiException::ClientError.new(self, { some: 'details', more: 'stuff' }, 404)

ex.transient #=> false

ex = YetiException::ClientError.new(self, { some: 'details', more: 'stuff' })

ex.http_status #=> 400

Custom subclasses can be useful if you want to handle specific exceptions differently.

class MySpecialError < YetiException::Error; end

begin
  do_something
rescue MySpecialError => ex
  puts "Special: #{ex.message}"
rescue => ex
  puts "Not so special: #{ex.message}"
end

Custom subclasses can also define a static message that will be merged into the exception's details hash automatically.

class MySpecialError < YetiException::Error
  def msg
    'Something special'
  end
end

ex = MySpecialError.new(self, { some: 'details' })

ex.details #=> {:msg=>"Something special", :some=>"details"} 

The static message will not overwrite a :msg key included explicitly in the details.

class MySpecialError < YetiException::Error
  def msg
    'Something special'
  end
end

ex = MySpecialError.new(self, { some: 'details', msg: 'Even more special' })

ex.details #=> {:msg=>"Even more special", :some=>"details"}

The YetiException::Helpers mixin

YetiException::Helpers is a mixin that provides a raise_exception convenience method, defined as both a class and instance method.

YetiException::Error has a klass attribute containing the class in which the exception was raised so that it may be used in log searching. While the raising class can be inferred from the exception's backtrace, the class name is more intuitive. raise_exception removes the need to reference the class explicitly.

class MyClass
  include YetiException::Helpers

  def call
    raise_exception(YetiException::Error, { some: 'details' })
  end
end

ex = begin
  MyClass.new.call
rescue => exception
  exception
end

ex.klass #=> MyClass

Any YetiException::Error subclass can be raised, and additional parameters are passed to the exception's #initialize method:

raise_exception(MyCustomError,             # exception class
                { some: 'details' },       # details
                false,                     # transient
                400)                       # HTTP status

Integration with YetiLogger

YetiException was designed with YetiLogger in mind. YetiLogger automatically handles logging a details hash with an optional exception.

begin
  do_something
rescue YetiException::Error => ex
  log_error(ex.details, ex)
end

The class in which the exception was raised can also be included.

begin
  do_something
rescue YetiException::Error => ex
  log_error(ex.details.merge(klass: ex.klass), ex)
end

Integration with Ruby on Rails controllers

The http_status attribute of YetiException::Error can be used when rescuing an exception in a Rails controller. If your application uses YetiException for all errors, it makes sense to define a rescue_from hander in ApplicationController. For example, for an API-only app:

class ApplicationController < ActionController::API

  # Define a catch-all handler for other exceptions.  Rails searches for a
  # matching handler in the reverse order of their definitions.
  rescue_from StandardError do |ex|
    # If yeti_logger is used
    log_error({
                msg: 'error',
                error: ex.message
              }, ex)
    render json: { error: ex.message }, status: 500
  end

  # For the YetiException exceptions with richer data, use the specified
  # details and status.
  rescue_from YetiException::Error do |ex|
    # If yeti_logger is used
    log_error(ex.details, ex)
    render json: { error: ex.details }, status: ex.status
  end
end

Integration with asynchronous job frameworks

For asynchronous job frameworks like Sidekiq or Sneakers, exceptions can be caught in the worker entry point, and the transient attribute can be used to retry the job or fail it outright.

A framework-agnostic example:

class MyWorker
  def entry_point
    do_something
  rescue YetiException::Error => ex

    # If yeti_logger is used
    log_error(ex.details, ex)


    if ex.transient

      # retry the job

    else

      # fail the job

    end
  end
end

Contributing

  1. Fork it ( https://github.com/Yesware/yeti_exception/fork )
  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 a new Pull Request

yeti_exception's People

Contributors

cubicfeat avatar faustus7 avatar lmelnyk-va avatar mkostick avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.