Repository: rails/rails
File: activesupport/lib/active_support/error_reporter.rb (Ruby)

Code before:
    # Update the execution context that is accessible to error subscribers. Any
    # context passed to #handle, #record, or #report will be merged with the
    # context set here.
    #
    #   Rails.error.set_context(section: "checkout", user_id: @user.id)
    #
    def set_context(...)
      ActiveSupport::ExecutionContext.set(...)
    end

    # Report an error directly to subscribers. You can use this method when the
    # block-based #handle and #record methods are not suitable.
    #
    #   Rails.error.report(error)
    #
    def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
      return if error.instance_variable_defined?(:@__rails_error_reported)
      ensure_backtrace(error)

      unless SEVERITIES.include?(severity)
        raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
      end

      full_context = ActiveSupport::ExecutionContext.to_h.merge(context)
      disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
      @subscribers.each do |subscriber|
        unless disabled_subscribers&.any? { |s| s === subscriber }
          subscriber.report(error, handled: handled, severity: severity, context: full_context, source: source)
        end
      rescue => subscriber_error
        if logger
          logger.fatal(
            "Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})\n" +
            subscriber_error.backtrace.join("\n")
          )
        else
          raise
        end
      end

      while error
        unless error.frozen?
          error.instance_variable_set(:@__rails_error_reported, true)
        end
        error = error.cause
      end

      nil
    end

    private

Review comment (suggestion):
This is too defensive for my taste. It is documented `context` is a hash (at least the default argument), so instead of adding runtime overhead for proper users of this method, lets just make sure the argument are documented properly.

Code after:
    # Update the execution context that is accessible to error subscribers. Any
    # context passed to #handle, #record, or #report will be merged with the
    # context set here.
    #
    #   Rails.error.set_context(section: "checkout", user_id: @user.id)
    #
    def set_context(...)
      ActiveSupport::ExecutionContext.set(...)
    end

    # Report an error directly to subscribers. You can use this method when the
    # block-based #handle and #record methods are not suitable.
    #
    #   Rails.error.report(error)
    #
    def report(error, handled: true, severity: handled ? :warning : :error, context: {}, source: DEFAULT_SOURCE)
      return if error.instance_variable_defined?(:@__rails_error_reported)
      raise ArgumentError, "Reported error must be an Exception, got: #{error.inspect}" unless error.is_a?(Exception)

      ensure_backtrace(error)

      unless SEVERITIES.include?(severity)
        raise ArgumentError, "severity must be one of #{SEVERITIES.map(&:inspect).join(", ")}, got: #{severity.inspect}"
      end

      full_context = ActiveSupport::ExecutionContext.to_h.merge(context || {})
      disabled_subscribers = ActiveSupport::IsolatedExecutionState[self]
      @subscribers.each do |subscriber|
        unless disabled_subscribers&.any? { |s| s === subscriber }
          subscriber.report(error, handled: handled, severity: severity, context: full_context, source: source)
        end
      rescue => subscriber_error
        if logger
          logger.fatal(
            "Error subscriber raised an error: #{subscriber_error.message} (#{subscriber_error.class})\n" +
            subscriber_error.backtrace.join("\n")
          )
        else
          raise
        end
      end

      while error
        unless error.frozen?
          error.instance_variable_set(:@__rails_error_reported, true)
        end
        error = error.cause
      end

      nil
    end