You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The [error reporter](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html) collects exceptions occur in Ruby on Rails applications and reports them to registered subscribers.
21
-
22
-
The goals are to
18
+
The Rails [error reporter](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html) provides a standard way to collect exceptions that occur in your application and report them to your preferred service or location.
23
19
24
-
1. Automatically capture and report any unhandled exception from a controller or a job.
20
+
The error reporter aims to replace boilerplate error-handling code like this:
25
21
26
-
2. Replace such manual rescue in applications and libraries
27
-
28
-
```rb
22
+
```ruby
29
23
begin
30
24
do_something
31
25
rescueSomethingIsBroken => error
32
26
MyErrorReportingService.notify(error)
33
27
end
34
28
```
35
29
36
-
with
30
+
with a consistent interface:
37
31
38
-
```rb
32
+
```ruby
39
33
Rails.error.handle(SomethingIsBroken) do
40
34
do_something
41
35
end
42
36
```
43
37
44
-
This approach provides several benefits:
38
+
Rails wraps all executions (such as HTTP requests, jobs, and `rails runner` invocations) in the error reporter, so any unhandled errors raised in your app will automatically be reported to your error-reporting service via their subscribers.
39
+
40
+
This means that third-party error-reporting libraries no longer need to insert a Rack middleware or do any monkey-patching to capture unhandled exceptions. Libraries that use ActiveSupport can also use this to non-intrusively report warnings that would previously have been lost in logs.
45
41
46
-
* Application or error reporting libraries don't need to insert a Rack middleware to capture unhandled exceptions from requests anymore.
47
-
* To ActiveSupport-aware libraries, this can be used to report errors to the host application.
48
-
* It decouples application code from error reporting libraries.
49
-
* It reduces boilerplate code for handling exceptions.
50
-
* Error reporting libraries will need less monkey-patches and be less intrusive to applications.
42
+
Using the Rails' error reporter is not required. All other means of capturing errors still work.
51
43
52
-
### Subscribe To The Reporter
44
+
### Subscribing to the Reporter
53
45
54
-
An error subscriber is expected to have a `report` method that takes an exception object and a few options.
55
-
For example:
46
+
To use the error reporter, you need a _subscriber_. A subscriber is any object with a `report` method. When an error occurs in your application or is manually reported, the Rails error reporter will call this method with the error object and some options.
56
47
57
-
```rb
48
+
Some error-reporting libraries, such as [Sentry's](https://github.com/getsentry/sentry-ruby/blob/e18ce4b6dcce2ebd37778c1e96164684a1e9ebfc/sentry-rails/lib/sentry/rails/error_subscriber.rb) and [Honeybadger's](https://docs.honeybadger.io/lib/ruby/integration-guides/rails-exception-tracking/), automatically register a subscriber for you. Consult your provider's documentation for more details.
49
+
50
+
You may also create a custom subscriber. For example:
After defining the subscriber class, you can register its instance with the [`#subscribe`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-subscribe) method:
61
+
After defining the subscriber class, register it by calling [`Rails.error.subscribe`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-subscribe) method:
67
62
68
-
```rb
63
+
```ruby
69
64
Rails.error.subscribe(ErrorSubscriber.new)
70
65
```
71
66
72
-
To test the error subscriber, try this in Rails console:
73
-
74
-
```
75
-
irb(main):001:0> Rails.error.handle { raise }
76
-
```
77
-
78
-
And see if the error is reported to the service you use.
79
-
80
-
#### Libraries Subscribe To Rails Reporter
67
+
You can register as many subscribers as you wish. Rails will call them in turn, in the order in which they were registered.
81
68
82
-
Some libraries may provide their own subscriber classes. Please check their documentation for more information.
69
+
Note: The Rails error-reporter will always call registered subscribers, regardless of your environment. However, many error-reporting services only report errors in production by default. You should configure and test your setup across environments as needed.
There are three ways you can use the error reporter:
87
74
88
-
You can wrap your code inside a block with the reporting APIs, which will report the exceptions surface from the block.
75
+
#### Reporting and swallowing errors
76
+
[`Rails.error.handle`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-handle) will report any error raised within the block. It will then **swallow** the error, and the rest of your code outside the block will continue as normal.
89
77
90
-
To report and **swallow** the error, use [`Rails.error.handle`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-handle):
91
-
92
-
```rb
93
-
Rails.error.handle do
78
+
```ruby
79
+
result =Rails.error.handle do
94
80
1+'1'# raises TypeError
95
81
end
82
+
result # => nil
96
83
1+1# This will be executed
97
84
```
98
85
99
-
The error will be reported with `handled: true`
86
+
If no error is raised in the block, `Rails.error.handle`will return the result of the block, otherwise it will return `nil`. You can override this by providing a `fallback`:
100
87
101
-
To report but **not swallow** the error, use [`Rails.error.record`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-record):
88
+
```ruby
89
+
user =Rails.error.handle(fallback:-> { User.anonymous }) do
90
+
User.find_by(params[:id])
91
+
end
92
+
```
102
93
103
-
```rb
94
+
#### Reporting and re-raising errors
95
+
[`Rails.error.record`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-record) will report errors to all registered subscribers and then re-raise the error, meaning that the rest of your code won't execute.
96
+
97
+
```ruby
104
98
Rails.error.record do
105
99
1+'1'# raises TypeError
106
100
end
107
101
1+1# This won't be executed
108
102
```
109
103
110
-
The error will be reported with `handled: false`
104
+
If no error is raised in the block, `Rails.error.record` will return the result of the block.
111
105
112
-
If you decide to rescue the exception manually, you can also report it with [`Rails.error.report`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-report):
106
+
#### Manually reporting errors
107
+
You can also manually report errors by calling [`Rails.error.report`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-report):
113
108
114
-
```rb
109
+
```ruby
115
110
begin
116
111
# code
117
112
rescueStandardError => e
118
113
Rails.error.report(e)
119
114
end
120
115
```
121
116
122
-
#### Options
117
+
Any options you pass will be passed on the error subscribers.
118
+
119
+
### Error-reporting options
123
120
124
-
All 3 reporting APIs (`#handle`, `#record`, and `#report`) support the same options:
121
+
All 3 reporting APIs (`#handle`, `#record`, and `#report`) support the following options, which are then passed along to all registered subscribers:
125
122
126
-
-`handled`: a `Boolean` to tell if the error was handled
127
-
-`severity`: a `Symbol` about the severity of the exception. Expected values are: `:error`, `:warning`, and `:info`
128
-
-`context`: a `Hash` to provide more context about the error, like request headers or record attributes
129
-
-`source`: a `String` about the source of the exception. Default is `"application"`
130
-
- You can use it to skip exceptions from certain sources
123
+
-`handled`: a `Boolean` to indicate if the error was handled. This is set to `true` by default. `#record` sets this to `false`.
124
+
-`severity`: a `Symbol` describing the severity of the error. Expected values are: `:error`, `:warning`, and `:info`. `#handle` sets this to `:warning`, while `#record` sets it to `:error`.
125
+
-`context`: a `Hash` to provide more context about the error, like request or user details
126
+
-`source`: a `String` about the source of the error. The default source is `"application"`. Errors reported by internal libraries may set other sources; the Redis cache library may use `"redis_cache_store.active_support"`, for instance. Your subscriber can use the source to ignore errors you aren't interested in.
131
127
132
-
### Setting Context
128
+
```ruby
129
+
Rails.error.handle(context: {user_id: user.id}, severity::info) do
130
+
# ...
131
+
end
132
+
```
133
133
134
-
In addition to setting context through the `context` option, you can also use the [`#set_context`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-set_context) API. For example:
134
+
### Filtering by Error Class
135
135
136
-
```rb
136
+
With `Rails.error.handle` and `Rails.error.record`, you can also choose to only report errors of a certain class. For example:
137
+
138
+
```ruby
139
+
Rails.error.handle(IOError) do
140
+
1+'1'# raises TypeError
141
+
end
142
+
1+1# TypeErrors are not IOErrors, so this will *not* be executed
143
+
```
144
+
145
+
Here, the `TypeError` will not be captured by the Rails error reporter. Only instances of `IOError` and its descendants will be reported. Any other errors will be raised as normal.
146
+
147
+
### Setting Context Globally
148
+
149
+
In addition to setting context through the `context` option, you can use the [`#set_context`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-set_context) API. For example:
The context set this way will be merged with the `context` option
155
+
Any context set this way will be merged with the `context` option
141
156
142
-
```rb
157
+
```ruby
143
158
Rails.error.set_context(a:1)
144
159
Rails.error.handle(context: { b:2 }) { raise }
145
-
# the reported context will be: {:a=>1, :b=>2}
160
+
# The reported context will be: {:a=>1, :b=>2}
161
+
Rails.error.handle(context: { b:3 }) { raise }
162
+
# The reported context will be: {:a=>1, :b=>3}
146
163
```
147
164
148
165
### For Libraries
149
166
150
-
Libraries can easily register their subscribers in `Railtie`:
167
+
Error-reporting libraries can register their subscribers in a`Railtie`:
151
168
152
-
```rb
169
+
```ruby
153
170
moduleMySdk
154
171
classRailtie < ::Rails::Railtie
155
172
initializer "error_subscribe.my_sdk"do
@@ -158,3 +175,5 @@ module MySdk
158
175
end
159
176
end
160
177
```
178
+
179
+
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.
0 commit comments