mirror of https://github.com/rails/rails
Allow ErrorReporter to handle several error classes
`Rails.error.handle` and `Rails.error.record` are able to filter by list of serveral error classes now, for example like this: ```ruby Rails.error.handle(ArgumentError, TypeError) do [1, 2, 3].first(x) # where `x` might be `-4` or `'4'` end ```
This commit is contained in:
parent
b96ddea5f0
commit
1a9b887c0c
|
@ -1,3 +1,14 @@
|
||||||
|
* `Rails.error.handle` and `Rails.error.record` filter now by multiple error classes.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Rails.error.handle(IOError, ArgumentError) do
|
||||||
|
1 + '1' # raises TypeError
|
||||||
|
end
|
||||||
|
1 + 1 # TypeErrors are not IOErrors or ArgumentError, so this will *not* be handled
|
||||||
|
```
|
||||||
|
|
||||||
|
*Martin Spickermann*
|
||||||
|
|
||||||
* `Class#subclasses` and `Class#descendants` now automatically filter reloaded classes.
|
* `Class#subclasses` and `Class#descendants` now automatically filter reloaded classes.
|
||||||
|
|
||||||
Previously they could return old implementations of reloadable classes that have been
|
Previously they could return old implementations of reloadable classes that have been
|
||||||
|
|
|
@ -42,7 +42,7 @@ module ActiveSupport
|
||||||
# 1 + '1'
|
# 1 + '1'
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# Can be restricted to handle only a specific error class:
|
# Can be restricted to handle only specific error classes:
|
||||||
#
|
#
|
||||||
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
# maybe_tags = Rails.error.handle(Redis::BaseError) { redis.get("tags") }
|
||||||
#
|
#
|
||||||
|
@ -69,9 +69,10 @@ module ActiveSupport
|
||||||
# * +:source+ - This value is passed along to subscribers to indicate the
|
# * +:source+ - This value is passed along to subscribers to indicate the
|
||||||
# source of the error. Subscribers can use this value to ignore certain
|
# source of the error. Subscribers can use this value to ignore certain
|
||||||
# errors. Defaults to <tt>"application"</tt>.
|
# errors. Defaults to <tt>"application"</tt>.
|
||||||
def handle(error_class = StandardError, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
|
def handle(*error_classes, severity: :warning, context: {}, fallback: nil, source: DEFAULT_SOURCE)
|
||||||
|
error_classes = [StandardError] if error_classes.blank?
|
||||||
yield
|
yield
|
||||||
rescue error_class => error
|
rescue *error_classes => error
|
||||||
report(error, handled: true, severity: severity, context: context, source: source)
|
report(error, handled: true, severity: severity, context: context, source: source)
|
||||||
fallback.call if fallback
|
fallback.call if fallback
|
||||||
end
|
end
|
||||||
|
@ -84,7 +85,7 @@ module ActiveSupport
|
||||||
# 1 + '1'
|
# 1 + '1'
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# Can be restricted to handle only a specific error class:
|
# Can be restricted to handle only specific error classes:
|
||||||
#
|
#
|
||||||
# tags = Rails.error.record(Redis::BaseError) { redis.get("tags") }
|
# tags = Rails.error.record(Redis::BaseError) { redis.get("tags") }
|
||||||
#
|
#
|
||||||
|
@ -104,9 +105,10 @@ module ActiveSupport
|
||||||
# * +:source+ - This value is passed along to subscribers to indicate the
|
# * +:source+ - This value is passed along to subscribers to indicate the
|
||||||
# source of the error. Subscribers can use this value to ignore certain
|
# source of the error. Subscribers can use this value to ignore certain
|
||||||
# errors. Defaults to <tt>"application"</tt>.
|
# errors. Defaults to <tt>"application"</tt>.
|
||||||
def record(error_class = StandardError, severity: :error, context: {}, source: DEFAULT_SOURCE)
|
def record(*error_classes, severity: :error, context: {}, source: DEFAULT_SOURCE)
|
||||||
|
error_classes = [StandardError] if error_classes.blank?
|
||||||
yield
|
yield
|
||||||
rescue error_class => error
|
rescue *error_classes => error
|
||||||
report(error, handled: false, severity: severity, context: context, source: source)
|
report(error, handled: false, severity: severity, context: context, source: source)
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,6 +68,23 @@ class ErrorReporterTest < ActiveSupport::TestCase
|
||||||
assert_equal [], @subscriber.events
|
assert_equal [], @subscriber.events
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "#handle can be scoped to several exception classes" do
|
||||||
|
assert_raises ArgumentError do
|
||||||
|
@reporter.handle(NameError, NoMethodError) do
|
||||||
|
raise ArgumentError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal [], @subscriber.events
|
||||||
|
end
|
||||||
|
|
||||||
|
test "#handle swallows and reports matching errors" do
|
||||||
|
error = ArgumentError.new("Oops")
|
||||||
|
@reporter.handle(NameError, ArgumentError) do
|
||||||
|
raise error
|
||||||
|
end
|
||||||
|
assert_equal [[error, true, :warning, "application", {}]], @subscriber.events
|
||||||
|
end
|
||||||
|
|
||||||
test "#handle passes through the return value" do
|
test "#handle passes through the return value" do
|
||||||
result = @reporter.handle do
|
result = @reporter.handle do
|
||||||
2 + 2
|
2 + 2
|
||||||
|
@ -125,6 +142,25 @@ class ErrorReporterTest < ActiveSupport::TestCase
|
||||||
assert_equal [], @subscriber.events
|
assert_equal [], @subscriber.events
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "#record can be scoped to several exception classes" do
|
||||||
|
assert_raises ArgumentError do
|
||||||
|
@reporter.record(NameError, NoMethodError) do
|
||||||
|
raise ArgumentError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal [], @subscriber.events
|
||||||
|
end
|
||||||
|
|
||||||
|
test "#record report any matching, unhandled error and re-raise them" do
|
||||||
|
error = ArgumentError.new("Oops")
|
||||||
|
assert_raises ArgumentError do
|
||||||
|
@reporter.record(NameError, ArgumentError) do
|
||||||
|
raise error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert_equal [[error, false, :error, "application", {}]], @subscriber.events
|
||||||
|
end
|
||||||
|
|
||||||
test "#record passes through the return value" do
|
test "#record passes through the return value" do
|
||||||
result = @reporter.record do
|
result = @reporter.record do
|
||||||
2 + 2
|
2 + 2
|
||||||
|
|
|
@ -131,9 +131,9 @@ Rails.error.handle(context: {user_id: user.id}, severity: :info) do
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
### Filtering by Error Class
|
### Filtering by Error Classes
|
||||||
|
|
||||||
With `Rails.error.handle` and `Rails.error.record`, you can also choose to only report errors of a certain class. For example:
|
With `Rails.error.handle` and `Rails.error.record`, you can also choose to only report errors of certain classes. For example:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
Rails.error.handle(IOError) do
|
Rails.error.handle(IOError) do
|
||||||
|
@ -176,4 +176,4 @@ module MySdk
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
If you register an error subscriber, but still have other error mechanisms like a Rack middleware, you may end up with errors reported multiple times. You should either remove your other mechanisms or adjust your report functionality so it skips reporting an exception it has seen before.
|
If you register an error subscriber, but still have other error mechanisms like a Rack middleware, you may end up with errors reported multiple times. You should either remove your other mechanisms or adjust your report functionality so it skips reporting an exception it has seen before.
|
||||||
|
|
Loading…
Reference in New Issue