Class: ActiveSupport::ErrorReporter

Inherits:
Object
  • Object
show all
Defined in:
lib/active_support/error_reporter.rb

Overview

ActiveSupport::ErrorReporter is a common interface for error reporting services.

To rescue and report any unhandled error, you can use the handle method:

Rails.error.handle do
  do_something!
end

If an error is raised, it will be reported and swallowed.

Alternatively if you want to report the error but not swallow it, you can use record

Rails.error.record do
  do_something!
end

Both methods can be restricted to only handle a specific exception class

maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }

You can also pass some extra context information that may be used by the error subscribers:

Rails.error.handle(context: { section: "admin" }) do
  # ...
end

Additionally a severity can be passed along to communicate how important the error report is. severity can be one of :error, :warning, or :info. Handled errors default to the :warning severity, and unhandled ones to :error.

Both handle and record pass through the return value from the block. In the case of handle rescuing an error, a fallback can be provided. The fallback must be a callable whose result will be returned when the block raises and is handled:

user = Rails.error.handle(fallback: -> { User.anonymous }) do
  User.find_by(params)
end

Constant Summary collapse

SEVERITIES =
%i(error warning info)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*subscribers, logger: nil) ⇒ ErrorReporter

Returns a new instance of ErrorReporter.


46
47
48
49
# File 'lib/active_support/error_reporter.rb', line 46

def initialize(*subscribers, logger: nil)
  @subscribers = subscribers.flatten
  @logger = logger
end

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.


44
45
46
# File 'lib/active_support/error_reporter.rb', line 44

def logger
  @logger
end

Instance Method Details

#handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil) ⇒ Object

Report any unhandled exception, and swallow it.

Rails.error.handle do
  1 + '1'
end

57
58
59
60
61
62
# File 'lib/active_support/error_reporter.rb', line 57

def handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil)
  yield
rescue error_class => error
  report(error, handled: true, severity: severity, context: context)
  fallback.call if fallback
end

#record(error_class = StandardError, severity: :error, context: {}) ⇒ Object


64
65
66
67
68
69
# File 'lib/active_support/error_reporter.rb', line 64

def record(error_class = StandardError, severity: :error, context: {})
  yield
rescue error_class => error
  report(error, handled: false, severity: severity, context: context)
  raise
end

#report(error, handled:, severity: handled ? :warning : :error, context: {}) ⇒ Object

When the block based handle and record methods are not suitable, you can directly use report

Rails.error.report(error, handled: true)

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/active_support/error_reporter.rb', line 95

def report(error, handled:, severity: handled ? :warning : :error, context: {})
  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)
  @subscribers.each do |subscriber|
    subscriber.report(error, handled: handled, severity: severity, context: full_context)
  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

  nil
end

#set_contextObject

Update the execution context that is accessible to error subscribers

Rails.error.set_context(section: "checkout", user_id: @user.id)

See ActiveSupport::ExecutionContext.set


88
89
90
# File 'lib/active_support/error_reporter.rb', line 88

def set_context(...)
  ActiveSupport::ExecutionContext.set(...)
end

#subscribe(subscriber) ⇒ Object

Register a new error subscriber. The subscriber must respond to

report(Exception, handled: Boolean, context: Hash)

The report method should never raise an error.


76
77
78
79
80
81
# File 'lib/active_support/error_reporter.rb', line 76

def subscribe(subscriber)
  unless subscriber.respond_to?(:report)
    raise ArgumentError, "Error subscribers must respond to #report"
  end
  @subscribers << subscriber
end