failsafe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ .rspec
2
+ Gemfile.lock
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - ree
4
+ - ruby-head
5
+ - rbx
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+ gem 'rake'
5
+
6
+ group :test do
7
+ gem 'rspec', ">= 2.7"
8
+ gem 'mocha'
9
+ end
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2012 Alex Sharp
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,64 @@
1
+ [![Build Status](https://secure.travis-ci.org/zaarly/failsafe.png?branch=master)](http://travis-ci.org/zaarly/failsafe)
2
+
3
+ ## What
4
+
5
+ Failsafe is a tiny library that makes it easy to make sure non-critical exceptions
6
+ don't interrupt program flow. It uses a failure handling system heavily inspired
7
+ by that of [Resque](http://github.com/defunkt/resque).
8
+
9
+ You can use failsafe to suppress exceptions from your users, but continue to deliver
10
+ them to your errors backends (log files, airbrake, etc).
11
+
12
+ ## Usage
13
+
14
+ ```ruby
15
+ Failsafe.error_backends << Failsafe::Backends::Stderr
16
+
17
+ class MyApp < Sinatra::Base
18
+ get '/' do
19
+ Failsafe.failsafe { track_some_metrics; raise("boom!") }
20
+ status(200)
21
+ end
22
+ end
23
+ ```
24
+
25
+ ## Disabling Failsafe
26
+
27
+ In production, you want your app to keep ticking along when certain exceptions
28
+ occur without missing a beat. However, in development and test environments,
29
+ you probably want to know that exceptions are occurring.
30
+ Use the `disabled` property for that:
31
+
32
+ ```ruby
33
+ if Rails.env.test?
34
+ Failsafe.disabled = true
35
+ else
36
+ # not necessary, this is the default setting
37
+ Failsafe.disabled = false
38
+ end
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ Failsafe comes with 3 error backends by default: Airbrake, File, and Stderr.
44
+ You must add them to the failsafe configuration in order to log exceptions
45
+ to them:
46
+
47
+ ```ruby
48
+ Failsafe.error_backends << Failsafe::Backends::Airbrake
49
+ Failsafe.error_backends << Failsafe::Backends::Stderr
50
+ ```
51
+
52
+ ## Backends
53
+
54
+ "Backends" are what your exceptions get handled by instead of letting them
55
+ bubble up to the user. When an exception occurs within a piece of code wrapped
56
+ by failsafe, the exception object is handed to each error backend.
57
+
58
+ Failsafe ships with three error backends by default:
59
+
60
+ * Airbrake - Send errors to airbrake
61
+ * Stderr - Send errors to stderr
62
+ * File - Send errors to a log file
63
+
64
+ Note: The File backend logs to a log file in the log directory called failsafe_errors.log.
@@ -0,0 +1,5 @@
1
+ require 'rake'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
5
+ task :default => :spec
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "failsafe/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "failsafe"
7
+ s.version = Failsafe::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Alex Sharp"]
10
+ s.email = ["ajsharp@gmail.com"]
11
+ s.homepage = "https://github.com/zaarly/failsafe"
12
+ s.summary = %q{Tiny little library for silently handling errors so they don't interrupt program flow.}
13
+ s.description = %q{}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+
3
+ require 'failsafe/failure'
4
+
5
+ module Failsafe
6
+
7
+ # Attach error backends to be fire when errors occur.
8
+ #
9
+ # @example Adding multiple backends
10
+ # Failsafe::Config.error_backends << Failsafe::Backends::Airbrake
11
+ # Failsafe::Config.error_backends << Failsafe::Backends::Stderr
12
+ def self.error_backends
13
+ @backends ||= []
14
+ end
15
+
16
+ @@disabled = false
17
+
18
+ # Determines if failsafe should rescue errors or let them bubble up.
19
+ #
20
+ # @default false
21
+ # @return [Boolean]
22
+ def self.disabled; @@disabled; end
23
+ def self.disabled?; disabled; end
24
+
25
+ def self.disabled=(val)
26
+ @@disabled = val
27
+ end
28
+
29
+ # Wraps code in a begin..rescue and delivers exceptions
30
+ # to the configured error backends.
31
+ #
32
+ # @todo make this threadsafe
33
+ def self.failsafe
34
+ # Let errors bubble up if failsafe has been disabled
35
+ if disabled?
36
+ return yield
37
+ end
38
+
39
+ begin
40
+ yield
41
+ rescue => e
42
+ error_backends.each do |backend|
43
+ backend.new(e).save
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Failsafe
2
+ module Backends
3
+
4
+ # Failure backend to send errors to Airbrake
5
+ class Airbrake < Base
6
+ def save
7
+ ::Airbrake.notify_or_ignore(exception)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Failsafe
2
+ module Backends
3
+ class Base
4
+ attr_accessor :exception
5
+
6
+ def initialize(exception)
7
+ @exception = exception
8
+ end
9
+
10
+ # Implement in subclasses
11
+ def save
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module Failsafe
2
+ module Backends
3
+
4
+ # File failure backend. Writes exception backtraces to a logfile.
5
+ class File < Base
6
+ def self.logger
7
+ @logger ||= ::Logger.new(::File.join(Rails.root, 'log', 'failsafe_errors.log')).tap { |l| l.formatter = Logger::Formatter.new }
8
+ end
9
+
10
+ def save
11
+ msg = []
12
+ msg << exception.message
13
+ msg << exception.backtrace.join("\n")
14
+ self.class.logger.error(msg.join)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+
2
+ module Failsafe
3
+ module Backends
4
+
5
+ # Failure backend to log errors to stderr
6
+ class Stderr < Base
7
+ def self.logger
8
+ @logger ||= ::Logger.new($stderr).tap { |l| l.formatter = Logger::Formatter.new }
9
+ end
10
+
11
+ def save
12
+ msg = []
13
+ msg << exception.message
14
+ msg << exception.backtrace.join("\n")
15
+ self.class.logger.error(msg.join)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ module Failsafe
2
+ module Backends
3
+ autoload :Base, 'failsafe/backends/base'
4
+
5
+ autoload :Airbrake, 'failsafe/backends/airbrake'
6
+ autoload :Stderr, 'failsafe/backends/stderr'
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module Failsafe
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Failsafe::Backends::Base do
4
+ subject { Failsafe::Backends::Base.new(Exception.new) }
5
+
6
+ it { should respond_to :save }
7
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Failsafe::Backends::Stderr do
4
+ let!(:stderr_bucket) { $stderr }
5
+ let(:exception) { RuntimeError.new("Oh noez!") }
6
+
7
+ subject { Failsafe::Backends::Stderr.new(exception) }
8
+
9
+ before do
10
+ $stderr = StringIO.new
11
+ Failsafe::Backends::Stderr.stubs(:logger => ::Logger.new($stderr))
12
+ exception.set_backtrace(["#{__FILE__}:6"])
13
+ subject.save
14
+ $stderr.rewind
15
+ end
16
+
17
+ after { $stderr = stderr_bucket }
18
+
19
+ it "logs something to stderr when a exception is raised" do
20
+ $stderr.read.should =~ /Oh noez!/
21
+ end
22
+
23
+ it "logs the backtrace" do
24
+ $stderr.read.should include "stderr_spec.rb:6"
25
+ end
26
+ end
27
+
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe "configuring error backends" do
4
+ it "adds the error backend class to the config" do
5
+ some_backend_class = Struct.new(:save)
6
+ Failsafe.error_backends << some_backend_class
7
+ Failsafe.error_backends.should include some_backend_class
8
+ end
9
+ end
10
+
11
+ describe Failsafe, ".failsafe" do
12
+ class DangerousClass
13
+ def boom_boom
14
+ raise RuntimeError.new "room!"
15
+ end
16
+ end
17
+
18
+ before { Failsafe.error_backends << MockFailureBackend }
19
+ let(:danger) { DangerousClass.new }
20
+
21
+ subject { Failsafe.failsafe { danger.boom_boom } }
22
+
23
+ it "does not raise an error when wrapped with failsafe" do
24
+ expect {
25
+ subject
26
+ }.not_to raise_error
27
+ end
28
+
29
+ it "notifies backends of the exception" do
30
+ MockFailureBackend.any_instance.expects(:save)
31
+ subject
32
+ end
33
+ end
34
+
35
+ describe "disabling failsafe" do
36
+ it "is not disabled by default" do
37
+ Failsafe.should_not be_disabled
38
+ end
39
+
40
+ context "when false" do
41
+ before { Failsafe.disabled = false }
42
+
43
+ it "allows exception to bubble up" do
44
+ expect {
45
+ Failsafe.failsafe { raise 'boom' }
46
+ }.not_to raise_error
47
+ end
48
+ end
49
+
50
+ context "when true" do
51
+ before { Failsafe.disabled = true }
52
+
53
+ it "allows errors to bubble up" do
54
+ expect {
55
+ Failsafe.failsafe { raise 'boom' }
56
+ }.to raise_error
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,12 @@
1
+ $:.push(File.expand_path(File.dirname(__FILE__)))
2
+ $:.push(File.expand_path(File.dirname(__FILE__)) + '/../lib')
3
+
4
+ require 'failsafe'
5
+
6
+ class MockFailureBackend < Failsafe::Backends::Base
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.mock_with :mocha
11
+ config.after { Failsafe.error_backends.clear }
12
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: failsafe
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alex Sharp
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-16 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ''
15
+ email:
16
+ - ajsharp@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - .rvmrc
23
+ - .travis.yml
24
+ - Gemfile
25
+ - MIT-LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - failsafe.gemspec
29
+ - lib/failsafe.rb
30
+ - lib/failsafe/backends/airbrake.rb
31
+ - lib/failsafe/backends/base.rb
32
+ - lib/failsafe/backends/file.rb
33
+ - lib/failsafe/backends/stderr.rb
34
+ - lib/failsafe/failure.rb
35
+ - lib/failsafe/version.rb
36
+ - spec/failsafe/backends/base_spec.rb
37
+ - spec/failsafe/backends/stderr_spec.rb
38
+ - spec/failsafe_spec.rb
39
+ - spec/spec_helper.rb
40
+ homepage: https://github.com/zaarly/failsafe
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.15
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Tiny little library for silently handling errors so they don't interrupt
64
+ program flow.
65
+ test_files:
66
+ - spec/failsafe/backends/base_spec.rb
67
+ - spec/failsafe/backends/stderr_spec.rb
68
+ - spec/failsafe_spec.rb
69
+ - spec/spec_helper.rb