класс ActiveSupport::ErrorReporter
Средство отправки сообщений об ошибках Active Support
ActiveSupport::ErrorReporter — это общий интерфейс для служб отправки сообщений об ошибках.
Чтобы перехватывать и отправлять отчёты о любых необработанных ошибках, можно использовать метод handle:
Rails.error.handle do do_something! end
Если возникнет ошибка, о ней будет отправлен отчёт, а сама ошибка будет подавлена.
Если нужно отправить отчёт об ошибке, но не подавлять её, можно использовать метод record:
Rails.error.record do do_something! end
Оба метода можно ограничить обработкой ошибок только определённого класса:
maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
Константы
- DEFAULT_RESCUE
- DEFAULT_SOURCE
- SEVERITIES
- UnexpectedError
Атрибуты
Открытые методы класса
# File activesupport/lib/active_support/error_reporter.rb, line 35 def initialize(*subscribers, logger: nil) @subscribers = subscribers.flatten @logger = logger @debug_mode = false @context_middlewares = ErrorContextMiddlewareStack.new end
Открытые методы экземпляра
# File activesupport/lib/active_support/error_reporter.rb, line 218 def add_middleware(middleware) @context_middlewares.use(middleware) end
Добавляет промежуточное ПО для изменения контекста ошибки перед его передачей подписчикам.
Промежуточное ПО добавляется в стек вызываемых объектов, которые выполняются в контексте выполнения ошибки перед передачей подписчикам. Оно позволяет создавать записи в контексте ошибки, общие для всех подписчиков.
Промежуточное ПО контекста получает те же параметры, что и report. Оно должно возвращать хеш — стек промежуточного ПО возвращает хеш после выполнения всех обработчиков. Промежуточное ПО может изменять хеш или заменять его.
Rails.error.add_middleware(-> (error, context) { context.merge({ foo: :bar }) })
# File activesupport/lib/active_support/error_reporter.rb, line 186
def disable(subscriber)
disabled_subscribers = (ActiveSupport::IsolatedExecutionState[self] ||= [])
disabled_subscribers << subscriber
begin
yield
ensure
disabled_subscribers.delete(subscriber)
end
end Запрещает уведомлять подписчика об ошибках на время выполнения блока. Можно передать самого подписчика или его класс.
Это может быть полезно при интеграции со службами отправки сообщений об ошибках, если они хотят самостоятельно обработать ошибки на более высоком уровне стека вызовов.
# File activesupport/lib/active_support/error_reporter.rb, line 79
def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
error_classes = DEFAULT_RESCUE if error_classes.empty?
yield
rescue *error_classes => error
report(error, handled: true, severity: severity, context: context, source: source)
fallback.call if fallback
end Выполняет указанный блок, отправляя отчёты обо всех необработанных ошибках и подавляя их. Если ошибка не возникла, возвращает значение, возвращённое блоком. В противном случае возвращает результат fallback.call или nil, если fallback не указан.
# Will report a TypeError to all subscribers and return nil. Rails.error.handle do 1 + '1' end
Можно ограничить обработку ошибок только определёнными классами:
maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
Параметры
-
:severity— это значение передаётся подписчикам, чтобы указать важность отчёта об ошибке. Возможные значения::error,:warningили:info. По умолчанию используется:warning. -
:context— дополнительные сведения, передаваемые подписчикам. Например:Rails.error.handle(context: { section: "admin" }) do # ... end -
:fallback— вызываемый объект, предоставляющий возвращаемое значениеhandleпри возникновении необработанной ошибки. Например:user = Rails.error.handle(fallback: -> { User.anonymous }) do User.find_by(params) end -
:source— это значение передаётся подписчикам, чтобы указать источник ошибки. Подписчики могут использовать это значение, чтобы игнорировать определённые ошибки. По умолчанию используется"application".
# File activesupport/lib/active_support/error_reporter.rb, line 115
def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
error_classes = DEFAULT_RESCUE if error_classes.empty?
yield
rescue *error_classes => error
report(error, handled: false, severity: severity, context: context, source: source)
raise
end Выполняет указанный блок, отправляя отчёты обо всех необработанных ошибках и повторно вызывая их. Если ошибка не возникла, возвращает значение, возвращённое блоком.
# Will report a TypeError to all subscribers and re-raise it. Rails.error.record do 1 + '1' end
Можно ограничить обработку ошибок только определёнными классами:
tags = Rails.error.record(Redis::BaseError) { redis.get("tags") }
Параметры
-
:severity— это значение передаётся подписчикам, чтобы указать важность отчёта об ошибке. Возможные значения::error,:warningили:info. По умолчанию используется:error. -
:context— дополнительные сведения, передаваемые подписчикам. Например:Rails.error.record(context: { section: "admin" }) do # ... end -
:source— это значение передаётся подписчикам, чтобы указать источник ошибки. Подписчики могут использовать это значение, чтобы игнорировать определённые ошибки. По умолчанию используется"application".
# File activesupport/lib/active_support/error_reporter.rb, line 233
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 = @context_middlewares.execute(
error,
context: ActiveSupport::ExecutionContext.to_h.merge(context || {}),
handled:,
severity:,
source:
)
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 Отправляет отчёт об ошибке напрямую подписчикам. Этот метод можно использовать, если методы на основе блоков handle и record не подходят.
Rails.error.report(error)
Аргумент error должен быть экземпляром Exception.
Rails.error.report(Exception.new("Something went wrong"))
В противном случае можно использовать unexpected для отправки отчёта об ошибке, которому можно передать строковый аргумент.
# File activesupport/lib/active_support/error_reporter.rb, line 202 def set_context(...) ActiveSupport::ExecutionContext.set(...) end
Обновляет контекст выполнения, доступный подписчикам на ошибки. Любой контекст, переданный в handle, record или report, будет объединён с заданным здесь контекстом.
Rails.error.set_context(section: "checkout", user_id: @user.id)
# File activesupport/lib/active_support/error_reporter.rb, line 162
def subscribe(subscriber)
unless subscriber.respond_to?(:report)
raise ArgumentError, "Error subscribers must respond to #report"
end
@subscribers << subscriber
end Регистрирует нового подписчика на ошибки. Подписчик должен отвечать на
report(Exception, handled: Boolean, severity: (:error OR :warning OR :info), context: Hash, source: String)
Метод report ни в коем случае не должен вызывать ошибку.
# File activesupport/lib/active_support/error_reporter.rb, line 146
def unexpected(error, severity: :warning, context: {}, source: DEFAULT_SOURCE)
error = RuntimeError.new(error) if error.is_a?(String)
if @debug_mode
ensure_backtrace(error)
raise UnexpectedError, "#{error.class.name}: #{error.message}", error.backtrace, cause: error
else
report(error, handled: true, severity: severity, context: context, source: source)
end
end Отправляет отчёт об указанной ошибке в production-окружении или вызывает её в окружении разработки либо тестирования.
При вызове в production-окружении после отправки отчёта этот метод возвращает nil, и выполнение продолжается.
При вызове в окружении разработки исходная ошибка оборачивается в ошибку другого класса, чтобы её нельзя было перехватить на более высоком уровне стека вызовов; ошибка будет показана разработчику.
Этот метод предназначен для сообщения о нарушении утверждений относительно предварительных условий и подобных случаях, которые можно и следует корректно обрабатывать в production-окружении, но которые не должны происходить.
В качестве ошибки можно передать экземпляр исключения или String.
example:
def edit
if published?
Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
return false
end
# ...
end # File activesupport/lib/active_support/error_reporter.rb, line 177
def unsubscribe(subscriber)
@subscribers.delete_if { |s| subscriber === s }
end Отменяет регистрацию подписчика на ошибки. Принимает подписчика или класс.
subscriber = MyErrorSubscriber.new Rails.error.subscribe(subscriber) Rails.error.unsubscribe(subscriber) # or Rails.error.unsubscribe(MyErrorSubscriber)
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.