safely-block-0.2.1/0000755000175000017500000000000013470475777014650 5ustar utkarsh2102utkarsh2102safely-block-0.2.1/lib/0000755000175000017500000000000013470475777015416 5ustar utkarsh2102utkarsh2102safely-block-0.2.1/lib/safely_block.rb0000644000175000017500000000007513470475777020402 0ustar utkarsh2102utkarsh2102require "safely/core" Object.send :include, Safely::Methods safely-block-0.2.1/lib/safely/0000755000175000017500000000000013470475777016701 5ustar utkarsh2102utkarsh2102safely-block-0.2.1/lib/safely/version.rb0000644000175000017500000000004613470475777020713 0ustar utkarsh2102utkarsh2102module Safely VERSION = "0.2.1" end safely-block-0.2.1/lib/safely/core.rb0000644000175000017500000000374013470475777020162 0ustar utkarsh2102utkarsh2102require "safely/version" require "errbase" require "digest" module Safely class << self attr_accessor :raise_envs, :tag, :report_exception_method, :throttle_counter attr_writer :env def report_exception(e, tag: nil) tag = Safely.tag if tag.nil? if tag && e.message e = e.dup # leave original exception unmodified message = e.message e.define_singleton_method(:message) do "[#{tag == true ? "safely" : tag}] #{message}" end end report_exception_method.call(e) end def env @env ||= ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" end def throttled?(e, options) return false unless options key = "#{options[:key] || Digest::MD5.hexdigest([e.class.name, e.message, e.backtrace.join("\n")].join("/"))}/#{(Time.now.to_i / options[:period]) * options[:period]}" throttle_counter.clear if throttle_counter.size > 1000 # prevent from growing indefinitely (throttle_counter[key] += 1) > options[:limit] end end DEFAULT_EXCEPTION_METHOD = proc do |e| Errbase.report(e) end self.tag = true self.report_exception_method = DEFAULT_EXCEPTION_METHOD self.raise_envs = %w(development test) # not thread-safe, but we don't need to be exact self.throttle_counter = Hash.new(0) module Methods def safely(tag: nil, sample: nil, except: nil, only: nil, silence: nil, throttle: false, default: nil) yield rescue *Array(only || StandardError) => e raise e if Array(except).any? { |c| e.is_a?(c) } raise e if Safely.raise_envs.include?(Safely.env) if sample ? rand < 1.0 / sample : true begin unless Array(silence).any? { |c| e.is_a?(c) } || Safely.throttled?(e, throttle) Safely.report_exception(e, tag: tag) end rescue => e2 $stderr.puts "FAIL-SAFE #{e2.class.name}: #{e2.message}" end end default end alias_method :yolo, :safely end extend Methods end safely-block-0.2.1/test/0000755000175000017500000000000013470475777015627 5ustar utkarsh2102utkarsh2102safely-block-0.2.1/test/test_helper.rb0000644000175000017500000000024013470475777020466 0ustar utkarsh2102utkarsh2102require "bundler/setup" Bundler.require(:default) require "minitest/autorun" require "minitest/pride" module Safely class TestError < StandardError; end end safely-block-0.2.1/test/safely_test.rb0000644000175000017500000000721113470475777020477 0ustar utkarsh2102utkarsh2102require_relative "test_helper" class TestSafely < Minitest::Test def setup Safely.env = "production" Safely.tag = true Safely.report_exception_method = Safely::DEFAULT_EXCEPTION_METHOD end def test_development_environment Safely.env = "development" assert_raises(Safely::TestError) do safely do raise Safely::TestError end end end def test_test_environment Safely.env = "test" assert_raises(Safely::TestError) do safely do raise Safely::TestError end end end def test_production_environment exception = Safely::TestError.new mock = MiniTest::Mock.new mock.expect :report_exception, nil, [exception] Safely.report_exception_method = -> (e) { mock.report_exception(e) } safely do raise exception end assert mock.verify end def test_yolo exception = Safely::TestError.new mock = MiniTest::Mock.new mock.expect :report_exception, nil, [exception] Safely.report_exception_method = -> (e) { mock.report_exception(e) } yolo do raise exception end assert mock.verify end def test_tagged ex = nil Safely.report_exception_method = -> (e) { ex = e } safely { raise Safely::TestError, "Boom" } assert_equal "[safely] Boom", ex.message end def test_not_tagged Safely.tag = false ex = nil Safely.report_exception_method = -> (e) { ex = e } safely { raise Safely::TestError, "Boom" } assert_equal "Boom", ex.message end def test_local_tag ex = nil Safely.report_exception_method = -> (e) { ex = e } safely(tag: "hi") { raise Safely::TestError, "Boom" } assert_equal "[hi] Boom", ex.message end def test_report_exception_tag ex = nil Safely.report_exception_method = -> (e) { ex = e } begin raise Safely::TestError, "Boom" rescue => e Safely.report_exception(e) end assert_equal "[safely] Boom", ex.message end def test_return_value assert_equal 1, safely { 1 } assert_nil safely { raise Safely::TestError, "Boom" } end def test_default assert_equal 1, safely(default: 2) { 1 } assert_equal 2, safely(default: 2) { raise Safely::TestError, "Boom" } end def test_only assert_nil safely(only: Safely::TestError) { raise Safely::TestError } assert_raises(RuntimeError, "Boom") { safely(only: Safely::TestError) { raise "Boom" } } end def test_only_array assert_nil safely(only: [Safely::TestError]) { raise Safely::TestError } assert_raises(RuntimeError, "Boom") { safely(only: [Safely::TestError]) { raise "Boom" } } end def test_except assert_raises(Safely::TestError, "Boom") { safely(except: StandardError) { raise Safely::TestError, "Boom" } } end def test_silence safely(silence: StandardError) { raise Safely::TestError, "Boom" } assert true end def test_failsafe Safely.report_exception_method = -> (_) { raise "oops" } _, err = capture_io do safely { raise "boom" } end assert_equal "FAIL-SAFE RuntimeError: oops\n", err end def test_throttle count = 0 Safely.report_exception_method = -> (_) { count += 1 } 5.times do |n| safely throttle: {limit: 2, period: 3600} do raise Safely::TestError end end assert_equal 2, count end def test_throttle_key count = 0 Safely.report_exception_method = -> (_) { count += 1 } 5.times do |n| safely throttle: {limit: 2, period: 3600, key: "boom#{n % 2}"} do raise Safely::TestError end end assert_equal 4, count end def test_bad_argument assert_raises(ArgumentError) do safely(unknown: true) { } end end end safely-block-0.2.1/CHANGELOG.md0000644000175000017500000000065513470475777016467 0ustar utkarsh2102utkarsh2102## 0.2.1 - Tag exceptions reported with `report_exception` ## 0.2.0 - Added `tag` option to `safely` method - Switched to keyword arguments - Fixed frozen string error - Fixed tagging with custom error handler ## 0.1.1 - Added `Safely.safely` to not pollute when included in gems - Added `throttle` option ## 0.1.0 - Added `tag` option and tag exception message by default - Added `except` option - Added `silence` option safely-block-0.2.1/Rakefile0000644000175000017500000000023413470475777016314 0ustar utkarsh2102utkarsh2102require "bundler/gem_tasks" require "rake/testtask" task default: :test Rake::TestTask.new do |t| t.libs << "test" t.pattern = "test/**/*_test.rb" end safely-block-0.2.1/LICENSE.txt0000644000175000017500000000205413470475777016474 0ustar utkarsh2102utkarsh2102Copyright (c) 2014 Andrew Kane MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. safely-block-0.2.1/README.md0000644000175000017500000000516113470475777016132 0ustar utkarsh2102utkarsh2102# Safely ```ruby safely do # keep going if this code fails end ``` Exceptions are rescued and automatically reported to your favorite reporting service. In development and test environments, exceptions are raised so you can fix them. [![Build Status](https://travis-ci.org/ankane/safely.svg?branch=master)](https://travis-ci.org/ankane/safely) ## Use It Everywhere “Oh no, analytics brought down search” ```ruby safely { track_search(params) } ``` “Recommendations stopped updating because of one bad user” ```ruby users.each do |user| safely { update_recommendations(user) } end ``` Also aliased as `yolo`. ## Features Specify a default value to return on exceptions ```ruby show_banner = safely(default: true) { show_banner_logic } ``` Raise specific exceptions ```ruby safely except: ActiveRecord::RecordNotUnique do # all other exceptions will be rescued end ``` Pass an array for multiple exception classes. Rescue only specific exceptions ```ruby safely only: ActiveRecord::RecordNotUnique do # all other exceptions will be raised end ``` Silence exceptions ```ruby safely silence: ActiveRecord::RecordNotUnique do # code end ``` Throttle reporting with: ```ruby safely throttle: {limit: 10, period: 1.minute} do # reports only first 10 exceptions each minute end ``` **Note:** The throttle limit is approximate and per process. ## Reporting Reports exceptions to a variety of services out of the box thanks to [Errbase](https://github.com/ankane/errbase). - [Airbrake](https://airbrake.io/) - [Appsignal](https://appsignal.com/) - [Bugsnag](https://bugsnag.com/) - [Exceptional](http://www.exceptional.io/) - [Honeybadger](https://www.honeybadger.io/) - [Opbeat](https://opbeat.com/) - [Raygun](https://raygun.io/) - [Rollbar](https://rollbar.com/) - [Sentry](https://getsentry.com/) Customize reporting with: ```ruby Safely.report_exception_method = -> (e) { Rollbar.error(e) } ``` By default, exception messages are prefixed with `[safely]`. This makes it easier to spot rescued exceptions. Turn this off with: ```ruby Safely.tag = false ``` To report exceptions manually: ```ruby Safely.report_exception(e) ``` ## Installation Add this line to your application’s Gemfile: ```ruby gem 'safely_block' ``` ## History View the [changelog](https://github.com/ankane/safely/blob/master/CHANGELOG.md) ## Contributing Everyone is encouraged to help improve this project. Here are a few ways you can help: - [Report bugs](https://github.com/ankane/safely/issues) - Fix bugs and [submit pull requests](https://github.com/ankane/safely/pulls) - Write, clarify, or fix documentation - Suggest or add new features safely-block-0.2.1/.travis.yml0000644000175000017500000000030213470475777016754 0ustar utkarsh2102utkarsh2102language: ruby rvm: 2.4.2 gemfile: - Gemfile sudo: false before_install: gem install bundler script: bundle exec rake test notifications: email: on_success: never on_failure: change safely-block-0.2.1/safely_block.gemspec0000644000175000017500000000165713470475777020663 0ustar utkarsh2102utkarsh2102# coding: utf-8 lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "safely/version" Gem::Specification.new do |spec| spec.name = "safely_block" spec.version = Safely::VERSION spec.authors = ["Andrew Kane"] spec.email = ["andrew@chartkick.com"] spec.summary = "Awesome exception handling" spec.description = "Awesome exception handling" spec.homepage = "https://github.com/ankane/safely" spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_dependency "errbase" spec.add_development_dependency "bundler", "~> 1.6" spec.add_development_dependency "rake" spec.add_development_dependency "minitest", ">= 5" end safely-block-0.2.1/.gitignore0000644000175000017500000000027113470475777016640 0ustar utkarsh2102utkarsh2102*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp *.bundle *.so *.o *.a mkmf.log safely-block-0.2.1/Gemfile0000644000175000017500000000014113470475777016137 0ustar utkarsh2102utkarsh2102source "https://rubygems.org" # Specify your gem's dependencies in safely_block.gemspec gemspec