diff --git a/README.md b/README.md index 874a177..52a36ce 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ You can configure Solid Errors via the Rails configuration object, under the `so * `email_subject_prefix` - Prefix added to the subject line for email notifications. See [Email notifications](#email-notifications) for more information. * `base_controller_class` - Specify a different controller as the base class for the Solid Errors controller. See [Authentication](#authentication) for more information. * `destroy_after` - If set, Solid Errors will periodically destroy resolved records that are older than the value specified. See [Automatically destroying old records](#automatically-destroying-old-records) for more information. +* `ignored_errors` - An array of error class names (strings) that will not be saved in addition to the default list hardcoded in `lib/solid_errors/subscriber.rb` ### Database Configuration @@ -376,4 +377,3 @@ The gem is available as open source under the terms of the [MIT License](https:/ ## Code of Conduct Everyone interacting in the SolidErrors project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fractaledmind/solid_errors/blob/main/CODE_OF_CONDUCT.md). - diff --git a/app/models/solid_errors/occurrence.rb b/app/models/solid_errors/occurrence.rb index 4f034e0..295ff94 100644 --- a/app/models/solid_errors/occurrence.rb +++ b/app/models/solid_errors/occurrence.rb @@ -5,6 +5,10 @@ class Occurrence < Record after_create_commit :send_email, if: -> { SolidErrors.send_emails? && SolidErrors.email_to.present? } after_create_commit :clear_resolved_errors, if: :should_clear_resolved_errors? + unless type_for_attribute("context").is_a?(ActiveRecord::Type::Json) + serialize :context, coder: JSON + end + # The parsed exception backtrace. Lines in this backtrace that are from installed gems # have the base path for gem installs replaced by "[GEM_ROOT]", while those in the project # have "[PROJECT_ROOT]". diff --git a/lib/solid_errors.rb b/lib/solid_errors.rb index c2a3788..dee56aa 100644 --- a/lib/solid_errors.rb +++ b/lib/solid_errors.rb @@ -15,6 +15,7 @@ module SolidErrors mattr_accessor :email_to mattr_accessor :email_subject_prefix mattr_accessor :destroy_after + mattr_writer :ignored_errors class << self # use method instead of attr_accessor to ensure @@ -29,6 +30,10 @@ def password @password ||= ENV["SOLIDERRORS_PASSWORD"] || @@password end + def ignored_errors + @ignored_errors ||= (@@ignored_errors || []).to_h{|k| [k,true]} + end + def send_emails? send_emails && email_to.present? end diff --git a/lib/solid_errors/subscriber.rb b/lib/solid_errors/subscriber.rb index 2063250..c8e8b0c 100644 --- a/lib/solid_errors/subscriber.rb +++ b/lib/solid_errors/subscriber.rb @@ -19,11 +19,10 @@ class Subscriber "CGI::Session::CookieStore::TamperedWithCookie", "Mongoid::Errors::DocumentNotFound", "Sinatra::NotFound", - "Sidekiq::JobRetry::Skip"].map(&:freeze).freeze + "Sidekiq::JobRetry::Skip"].to_h{|v| [v.freeze,true]}.freeze def report(error, handled:, severity:, context:, source: nil) return if ignore_by_class?(error.class.name) - error_attributes = { exception_class: error.class.name, message: s(error.message), @@ -49,11 +48,7 @@ def s(data) end def ignore_by_class?(error_class_name) - IGNORED_ERRORS.any? do |ignored_class| - ignored_class_name = ignored_class.respond_to?(:name) ? ignored_class.name : ignored_class - - ignored_class_name == error_class_name - end + SolidErrors.ignored_errors.key?(error_class_name) || IGNORED_ERRORS.key?(error_class_name) end end end diff --git a/test/models/solid_errors/occurrence_test.rb b/test/models/solid_errors/occurrence_test.rb index c994e7d..6cab4b5 100644 --- a/test/models/solid_errors/occurrence_test.rb +++ b/test/models/solid_errors/occurrence_test.rb @@ -39,6 +39,28 @@ def teardown end end + test "an ignored error should not be saved while an acceptable one is saved" do + SolidErrors.ignored_errors = ["RuntimeError"] + # An hardcoded ignored error should be discarded + assert_difference -> { SolidErrors::Error.count }, 0 do + assert_difference -> { SolidErrors::Occurrence.count }, 0 do + Rails.error.report( ActionController::RoutingError.new('argh')) + end + end + # A user ignored error should be discarded + assert_difference -> { SolidErrors::Error.count }, 0 do + assert_difference -> { SolidErrors::Occurrence.count }, 0 do + Rails.error.report( RuntimeError.new("argh") ) + end + end + # A valid error should be recorded + assert_difference -> { SolidErrors::Error.count }, +1 do + assert_difference -> { SolidErrors::Occurrence.count }, +1 do + Rails.error.report(StandardError.new("argh")) + end + end + end + private def simulate_99_old_exceptions(status) @@ -46,4 +68,5 @@ def simulate_99_old_exceptions(status) SolidErrors::Error.update_all(resolved_at: Time.current) if status == :resolved SolidErrors::Occurrence.last.update!(id: 99, created_at: 1.day.ago) end + end