diff --git a/activesupport/lib/active_support/error_reporter.rb b/activesupport/lib/active_support/error_reporter.rb index bb8ab05813..25ff0f51cb 100644 --- a/activesupport/lib/active_support/error_reporter.rb +++ b/activesupport/lib/active_support/error_reporter.rb @@ -80,6 +80,21 @@ module ActiveSupport @subscribers << subscriber end + # Prevent a subscriber from being notified of errors for the + # duration of the block. + # + # It can be used by error reporting service integration when they wish + # to handle the error higher in the stack. + def disable(subscriber) + disabled_subscribers = (ActiveSupport::IsolatedExecutionState[self] ||= []) + disabled_subscribers << subscriber + begin + yield + ensure + disabled_subscribers.delete(subscriber) + end + end + # Update the execution context that is accessible to error subscribers # # Rails.error.set_context(section: "checkout", user_id: @user.id) @@ -98,8 +113,11 @@ module ActiveSupport end full_context = ActiveSupport::ExecutionContext.to_h.merge(context) + disabled_subscribers = ActiveSupport::IsolatedExecutionState[self] @subscribers.each do |subscriber| - subscriber.report(error, handled: handled, severity: severity, context: full_context) + unless disabled_subscribers&.any? { |s| s === subscriber } + subscriber.report(error, handled: handled, severity: severity, context: full_context) + end rescue => subscriber_error if logger logger.fatal( diff --git a/activesupport/test/error_reporter_test.rb b/activesupport/test/error_reporter_test.rb index 50f605c772..4423db86a4 100644 --- a/activesupport/test/error_reporter_test.rb +++ b/activesupport/test/error_reporter_test.rb @@ -41,6 +41,20 @@ class ErrorReporterTest < ActiveSupport::TestCase assert_equal [[error, true, :warning, { section: "public" }]], @subscriber.events end + test "#disable allow to skip a subscriber" do + @reporter.disable(@subscriber) do + @reporter.report(ArgumentError.new("Oops"), handled: true) + end + assert_equal [], @subscriber.events + end + + test "#disable allow to skip a subscribers per class" do + @reporter.disable(ErrorSubscriber) do + @reporter.report(ArgumentError.new("Oops"), handled: true) + end + assert_equal [], @subscriber.events + end + test "#handle swallow and report any unhandled error" do error = ArgumentError.new("Oops") @reporter.handle do