safely_block-0.4.1/0000755000004100000410000000000014700510127014176 5ustar www-datawww-datasafely_block-0.4.1/lib/0000755000004100000410000000000014700510127014744 5ustar www-datawww-datasafely_block-0.4.1/lib/safely_block.rb0000644000004100000410000000014414700510127017725 0ustar www-datawww-datarequire_relative "safely/core" Object.include Safely::Methods Object.send :private, :safely, :yolo safely_block-0.4.1/lib/safely/0000755000004100000410000000000014700510127016227 5ustar www-datawww-datasafely_block-0.4.1/lib/safely/services.rb0000644000004100000410000000304014700510127020374 0ustar www-datawww-datamodule Safely DEFAULT_EXCEPTION_METHOD = proc do |e, info| begin Airbrake.notify(e, info) if defined?(Airbrake) if defined?(Appsignal) if Appsignal::VERSION.to_i >= 3 Appsignal.send_error(e) do |transaction| transaction.set_tags(info) end else Appsignal.send_error(e, info) end end if defined?(Bugsnag) Bugsnag.notify(e) do |report| report.add_tab(:info, info) if info.any? end end if defined?(Datadog::Tracing) Datadog::Tracing.active_span&.set_tags(info) Datadog::Tracing.active_span&.set_error(e) end ExceptionNotifier.notify_exception(e, data: info) if defined?(ExceptionNotifier) # TODO add info Google::Cloud::ErrorReporting.report(e) if defined?(Google::Cloud::ErrorReporting) Honeybadger.notify(e, context: info) if defined?(Honeybadger) NewRelic::Agent.notice_error(e, custom_params: info) if defined?(NewRelic::Agent) Raven.capture_exception(e, extra: info) if defined?(Raven) Raygun.track_exception(e, custom_data: info) if defined?(Raygun) Rollbar.error(e, info) if defined?(Rollbar) if defined?(ScoutApm::Error) # no way to add context for a single call # ScoutApm::Context.add(info) ScoutApm::Error.capture(e) end Sentry.capture_exception(e, extra: info) if defined?(Sentry) rescue => e $stderr.puts "[safely] Error reporting exception: #{e.class.name}: #{e.message}" end end end safely_block-0.4.1/lib/safely/core.rb0000644000004100000410000000413214700510127017504 0ustar www-datawww-data# stdlib require "digest" # modules require_relative "services" require_relative "version" module Safely class << self attr_accessor :raise_envs, :tag, :report_exception_method, :throttle_counter attr_writer :env def report_exception(e, tag: nil, context: {}) 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 if report_exception_method.arity == 1 report_exception_method.call(e) else report_exception_method.call(e, context) end 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 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, context: {}) 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, context: context) 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.4.1/lib/safely/version.rb0000644000004100000410000000004614700510127020241 0ustar www-datawww-datamodule Safely VERSION = "0.4.1" end safely_block-0.4.1/LICENSE.txt0000644000004100000410000000206114700510127016020 0ustar www-datawww-dataCopyright (c) 2014-2023 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.4.1/safely_block.gemspec0000644000004100000410000000202014700510127020172 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: safely_block 0.4.1 ruby lib Gem::Specification.new do |s| s.name = "safely_block".freeze s.version = "0.4.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Andrew Kane".freeze] s.date = "2024-09-05" s.email = "andrew@ankane.org".freeze s.files = ["CHANGELOG.md".freeze, "LICENSE.txt".freeze, "README.md".freeze, "lib/safely/core.rb".freeze, "lib/safely/services.rb".freeze, "lib/safely/version.rb".freeze, "lib/safely_block.rb".freeze] s.homepage = "https://github.com/ankane/safely".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 3".freeze) s.rubygems_version = "3.3.15".freeze s.summary = "Rescue and report exceptions in non-critical code".freeze end safely_block-0.4.1/README.md0000644000004100000410000000742514700510127015465 0ustar www-datawww-data# 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. [Read more](https://ankane.org/safely-pattern) [![Build Status](https://github.com/ankane/safely/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/safely/actions) ## Installation Add this line to your application’s Gemfile: ```ruby gem "safely_block" ``` ## 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(context: {user_id: user.id}) { update_recommendations(user) } end ``` Also aliased as `yolo` ## Features Pass extra context to be reported with exceptions ```ruby safely context: {user_id: 123} do # code end ``` 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. - [Airbrake](https://airbrake.io/) - [Appsignal](https://appsignal.com/) - [Bugsnag](https://bugsnag.com/) - [Datadog](https://www.datadoghq.com/product/error-tracking/) - [Exception Notification](https://github.com/smartinez87/exception_notification) - [Google Stackdriver](https://cloud.google.com/stackdriver/) - [Honeybadger](https://www.honeybadger.io/) - [New Relic](https://newrelic.com/) - [Raygun](https://raygun.io/) - [Rollbar](https://rollbar.com/) - [Scout APM](https://scoutapm.com/) - [Sentry](https://getsentry.com/) **Note:** Context is not supported with Google Stackdriver and Scout APM Customize reporting with: ```ruby Safely.report_exception_method = ->(e) { Rollbar.error(e) } ``` With Rails, you can add this in an initializer. 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) ``` ## Data Protection To protect the privacy of your users, do not send [personal data](https://en.wikipedia.org/wiki/Personally_identifiable_information) to exception services. Filter sensitive form fields, use ids (not email addresses) to identify users, and mask IP addresses. With Rollbar, you can do: ```ruby Rollbar.configure do |config| config.person_id_method = "id" # default config.scrub_fields |= [:birthday] config.anonymize_user_ip = true end ``` While working on exceptions, be on the lookout for personal data and correct as needed. ## 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 To get started with development and testing: ```sh git clone https://github.com/ankane/safely.git cd safely bundle install bundle exec rake test ``` safely_block-0.4.1/CHANGELOG.md0000644000004100000410000000144214700510127016010 0ustar www-datawww-data## 0.4.1 (2024-09-04) - Added support for Datadog ## 0.4.0 (2023-05-07) - Added exception reporting from [Errbase](https://github.com/ankane/errbase) - Dropped support for Ruby < 3 ## 0.3.0 (2019-10-28) - Made `safely` method private to behave like `Kernel` methods ## 0.2.2 (2019-08-06) - Added `context` option ## 0.2.1 (2018-02-25) - Tag exceptions reported with `report_exception` ## 0.2.0 (2017-02-21) - Added `tag` option to `safely` method - Switched to keyword arguments - Fixed frozen string error - Fixed tagging with custom error handler ## 0.1.1 (2016-05-14) - Added `Safely.safely` to not pollute when included in gems - Added `throttle` option ## 0.1.0 (2015-03-15) - Added `tag` option and tag exception message by default - Added `except` option - Added `silence` option