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
- 'For Libraries' is made into a top section and renamed 'Error-reporting Libraries'
- Various important paragraphs are reformatted into notes.
- To aid understanding for beginners, links are added when various concepts are referenced e.g. 'railties', 'jobs' etc.
- Sections are added on unexpected, unsubscribe and disable.
- Various wording tweaks are made for improved readability and easier understanding.
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.
provides a standard way to collect errors that occur in your application and
21
+
report them to your preferred service or location (e.g. you could report the
22
+
errors to a monitoring service such as
23
+
Sentry).
19
24
20
-
The error reporter aims to replace boilerplate error-handling code like this:
25
+
It aims to replace boilerplate error-handling code like this:
21
26
22
27
```ruby
23
28
begin
@@ -35,17 +40,32 @@ Rails.error.handle(SomethingIsBroken) do
35
40
end
36
41
```
37
42
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.
43
+
Rails wraps all executions (such as HTTP
44
+
requests,
45
+
[jobs](active_job_basics.html), and [rails runner](command_line.html#bin-rails-runner) invocations) in the error reporter,
46
+
so any unhandled errors raised in your app will automatically be reported to
47
+
your error-reporting service via their subscribers.
39
48
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.
49
+
This means that third-party error-reporting libraries no longer need to insert a
50
+
[Rack](rails_on_rack.html) middleware or do any monkey-patching to capture
51
+
unhandled errors. Libraries that use [Active
52
+
Support](https://api.rubyonrails.org/classes/ActiveSupport.html) can also use
53
+
this to non-intrusively report warnings that would previously have been lost in
54
+
logs.
41
55
42
-
Using the Rails' error reporter is not required. All other means of capturing errors still work.
56
+
NOTE: Using the Rails error reporter is optional, as other means of capturing
57
+
errors still work.
43
58
44
59
### Subscribing to the Reporter
45
60
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.
61
+
To use the error reporter with an external service, you need a _subscriber_. A
62
+
subscriber can be any Ruby object with a `report` method. When an error occurs
63
+
in your application or is manually reported, the Rails error reporter will call
64
+
this method with the error object and some options.
47
65
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.
66
+
NOTE: Some error-reporting libraries, such as Sentry's
67
+
and Honeybadger's,
68
+
automatically register a subscriber for you.
49
69
50
70
You may also create a custom subscriber. For example:
51
71
@@ -58,23 +78,51 @@ class ErrorSubscriber
58
78
end
59
79
```
60
80
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:
81
+
After defining the subscriber class, you can register it by calling the
This may be useful if you'd like to replace or remove a subscriber added by one
95
+
of your dependencies. Both `subscribe` and `unsubscribe` can take either a
96
+
subscriber or a class as follows:
97
+
98
+
```ruby
99
+
subscriber =ErrorSubscriber.new
100
+
Rails.error.unsubscribe(subscriber)
101
+
# or
102
+
Rails.error.unsubscribe(ErrorSubscriber)
103
+
```
68
104
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.
105
+
NOTE: The Rails error reporter will always call registered subscribers,
106
+
regardless of your environment. However, many error-reporting services only
107
+
report errors in production by default. You should configure and test your setup
108
+
across environments as needed.
70
109
71
110
### Using the Error Reporter
72
111
73
-
There are three ways you can use the error reporter:
112
+
Rails error reporter has four methods that allow you to report methods in
113
+
different ways:
114
+
115
+
*`Rails.error.handle`
116
+
*`Rails.error.record`
117
+
*`Rails.error.report`
118
+
*`Rails.error.unexpected`
74
119
75
120
#### Reporting and Swallowing Errors
76
121
77
-
[`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.
method will report any error raised within the block. It will then **swallow**
125
+
the error, and the rest of your code outside the block will continue as normal.
78
126
79
127
```ruby
80
128
result =Rails.error.handle do
@@ -84,7 +132,9 @@ result # => nil
84
132
1+1# This will be executed
85
133
```
86
134
87
-
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`:
135
+
If no error is raised in the block, `Rails.error.handle` will return the result
136
+
of the block, otherwise it will return `nil`. You can override this by providing
137
+
a `fallback`:
88
138
89
139
```ruby
90
140
user =Rails.error.handle(fallback:-> { User.anonymous }) do
@@ -94,7 +144,10 @@ end
94
144
95
145
#### Reporting and Re-raising Errors
96
146
97
-
[`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.
method will report errors to all registered subscribers and then **re-raise**
150
+
the error, meaning that the rest of your code won't execute.
98
151
99
152
```ruby
100
153
Rails.error.record do
@@ -103,11 +156,13 @@ end
103
156
1+1# This won't be executed
104
157
```
105
158
106
-
If no error is raised in the block, `Rails.error.record` will return the result of the block.
159
+
If no error is raised in the block, `Rails.error.record` will return the result
160
+
of the block.
107
161
108
162
#### Manually Reporting Errors
109
163
110
-
You can also manually report errors by calling [`Rails.error.report`](https://api.rubyonrails.org/classes/ActiveSupport/ErrorReporter.html#method-i-report):
All 3 reporting APIs (`#handle`, `#record`, and `#report`) support the following options, which are then passed along to all registered subscribers:
182
+
When called in production, this method will return nil after the error is
183
+
reported and the execution of your code will continue.
125
184
126
-
-`handled`: a `Boolean` to indicate if the error was handled. This is set to `true` by default. `#record` sets this to `false`.
127
-
-`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`.
128
-
-`context`: a `Hash` to provide more context about the error, like request or user details
129
-
-`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.
185
+
When called in development, the error will be wrapped in a new error class (to
186
+
ensure it's not being rescued higher in the stack) and surfaced to the developer
187
+
for debugging.
188
+
189
+
For example:
130
190
131
191
```ruby
132
-
Rails.error.handle(context: { user_id: user.id }, severity::info) do
192
+
defedit
193
+
if published?
194
+
Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
195
+
false
196
+
end
133
197
# ...
134
198
end
135
199
```
136
200
137
-
### Filtering by Error Classes
201
+
NOTE: This method is intended to gracefully handle any errors that may occur in
202
+
production, but that aren't anticipated to be the result of typical use.
138
203
139
-
With `Rails.error.handle` and `Rails.error.record`, you can also choose to only report errors of certain classes. For example:
204
+
### Error-reporting Options
205
+
206
+
The reporting APIs `#handle`, `#record`, and `#report` support the following
207
+
options, which are then passed along to all registered subscribers:
208
+
209
+
-`handled`: a `Boolean` to indicate if the error was handled. This is set to
210
+
`true` by default. `#record` sets this to `false`.
211
+
-`severity`: a `Symbol` describing the severity of the error. Expected values
212
+
are: `:error`, `:warning`, and `:info`. `#handle` sets this to `:warning`,
213
+
while `#record` sets it to `:error`.
214
+
-`context`: a `Hash` to provide more context about the error, like request or
215
+
user details
216
+
-`source`: a `String` about the source of the error. The default source is
217
+
`"application"`. Errors reported by internal libraries may set other sources;
218
+
the Redis cache library may use `"redis_cache_store.active_support"`, for
219
+
instance. Your subscriber can use the source to ignore errors you aren't
220
+
interested in.
140
221
141
222
```ruby
142
-
Rails.error.handle(IOError) do
143
-
1+'1'# raises TypeError
223
+
Rails.error.handle(context: { user_id: user.id }, severity::info) do
224
+
# ...
144
225
end
145
-
1+1# TypeErrors are not IOErrors, so this will *not* be executed
146
226
```
147
227
148
-
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.
149
-
150
228
### Setting Context Globally
151
229
152
-
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:
230
+
In addition to setting context through the `context` option, you can use
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.
297
+
NOTE: If you register an error subscriber, but still have other error mechanisms
298
+
like a Rack middleware, you may end up with errors reported multiple times. You
299
+
should either remove your other mechanisms or adjust your report functionality
300
+
so it skips reporting an error it has seen before.
0 commit comments