exceptify 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +16 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/CONTRIBUTING.md +33 -0
- data/MIT-LICENSE +23 -0
- data/README.md +534 -0
- data/RELEASING.md +51 -0
- data/Rakefile +25 -0
- data/docs/notifiers/custom.md +42 -0
- data/docs/notifiers/datadog.md +51 -0
- data/docs/notifiers/email.md +195 -0
- data/docs/notifiers/slack.md +154 -0
- data/docs/notifiers/sns.md +37 -0
- data/docs/notifiers/teams.md +54 -0
- data/docs/notifiers/webhook.md +60 -0
- data/exceptify.gemspec +48 -0
- data/lib/exceptify/base_notifier.rb +30 -0
- data/lib/exceptify/configuration.rb +184 -0
- data/lib/exceptify/datadog_notifier.rb +160 -0
- data/lib/exceptify/dispatcher.rb +49 -0
- data/lib/exceptify/email_notifier.rb +208 -0
- data/lib/exceptify/modules/backtrace_cleaner.rb +13 -0
- data/lib/exceptify/modules/error_grouping.rb +170 -0
- data/lib/exceptify/modules/formatter.rb +119 -0
- data/lib/exceptify/notification.rb +71 -0
- data/lib/exceptify/notifier.rb +19 -0
- data/lib/exceptify/notifier_registry.rb +55 -0
- data/lib/exceptify/rack.rb +88 -0
- data/lib/exceptify/rails/runner_tie.rb +57 -0
- data/lib/exceptify/rails.rb +29 -0
- data/lib/exceptify/rake.rb +59 -0
- data/lib/exceptify/request_context.rb +35 -0
- data/lib/exceptify/resque.rb +25 -0
- data/lib/exceptify/sidekiq.rb +15 -0
- data/lib/exceptify/slack_notifier.rb +141 -0
- data/lib/exceptify/sns_notifier.rb +98 -0
- data/lib/exceptify/solid_queue.rb +68 -0
- data/lib/exceptify/teams_notifier.rb +209 -0
- data/lib/exceptify/version.rb +5 -0
- data/lib/exceptify/views/exceptify/_backtrace.html.erb +3 -0
- data/lib/exceptify/views/exceptify/_backtrace.text.erb +1 -0
- data/lib/exceptify/views/exceptify/_data.html.erb +6 -0
- data/lib/exceptify/views/exceptify/_data.text.erb +1 -0
- data/lib/exceptify/views/exceptify/_environment.html.erb +10 -0
- data/lib/exceptify/views/exceptify/_environment.text.erb +5 -0
- data/lib/exceptify/views/exceptify/_request.html.erb +36 -0
- data/lib/exceptify/views/exceptify/_request.text.erb +10 -0
- data/lib/exceptify/views/exceptify/_session.html.erb +10 -0
- data/lib/exceptify/views/exceptify/_session.text.erb +2 -0
- data/lib/exceptify/views/exceptify/_title.html.erb +3 -0
- data/lib/exceptify/views/exceptify/_title.text.erb +3 -0
- data/lib/exceptify/views/exceptify/background_exceptify.html.erb +53 -0
- data/lib/exceptify/views/exceptify/background_exceptify.text.erb +14 -0
- data/lib/exceptify/views/exceptify/exceptify.html.erb +52 -0
- data/lib/exceptify/views/exceptify/exceptify.text.erb +24 -0
- data/lib/exceptify/webhook_notifier.rb +63 -0
- data/lib/exceptify.rb +177 -0
- data/lib/generators/exceptify/install_generator.rb +24 -0
- data/lib/generators/exceptify/templates/exceptify.rb.erb +44 -0
- metadata +364 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: dbf40071354c10947e6fa90ef8c512db08003e84322f1ade20637107db09deb5
|
|
4
|
+
data.tar.gz: 28a5b5cfe05a3012a4f5b88d9adda06b1fe7f6257beacd4a294c630b5a360f06
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3f7077257beead584f587c93f989c30908deb06264e5c254f8013bb84841a78dab7ed6eb4964fb04e3e48fab0debb7060851801c3cb55c333961dfbe30c641f1
|
|
7
|
+
data.tar.gz: de6d0cfb74a7be063254a5c7316e7b3ad3678754582648ef93bf05754065f78320d4357a623961cf247065f0f2e7c4fb11936df913efc6a9c74446c00c16a09d
|
data/CHANGELOG.rdoc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
== 1.0.0
|
|
2
|
+
|
|
3
|
+
First maintained release line under <tt>lukin-io/exceptify</tt>.
|
|
4
|
+
|
|
5
|
+
* Rename the gem, require paths, namespace, generator, templates, and documentation to <tt>exceptify</tt>.
|
|
6
|
+
* Require Ruby 3.4.4 or newer.
|
|
7
|
+
* Target Rails 8.0.2 or newer for development and verification, below Rails 9.
|
|
8
|
+
* Keep the supported notifier set focused on Email, Slack, Microsoft Teams, Amazon SNS, Datadog, Webhook, and custom notifiers.
|
|
9
|
+
* Remove unsupported notifier integrations and stale documentation.
|
|
10
|
+
* Add PORO configuration, notifier registry, dispatcher, notification, and request-context objects to keep core behavior testable.
|
|
11
|
+
* Add deterministic setup validation for network notifier options.
|
|
12
|
+
* Add dependency injection support for notifier clients/transports.
|
|
13
|
+
* Keep Rack middleware options isolated per middleware instance.
|
|
14
|
+
* Guard Rails runner hook installation from duplicate callbacks.
|
|
15
|
+
* Add Solid Queue support for reporting unhandled Active Job failures.
|
|
16
|
+
* Expand specs for success, failure, and edge/null/boundary behavior across the refactored core and supported notifiers.
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Contributor Code of Conduct
|
|
2
|
+
|
|
3
|
+
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
|
4
|
+
|
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
|
6
|
+
|
|
7
|
+
Examples of unacceptable behavior by participants include:
|
|
8
|
+
|
|
9
|
+
* The use of sexualized language or imagery
|
|
10
|
+
* Personal attacks
|
|
11
|
+
* Trolling or insulting/derogatory comments
|
|
12
|
+
* Public or private harassment
|
|
13
|
+
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
|
14
|
+
* Other unethical or unprofessional conduct.
|
|
15
|
+
|
|
16
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
|
17
|
+
|
|
18
|
+
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
|
19
|
+
|
|
20
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
|
21
|
+
|
|
22
|
+
This Code of Conduct is adapted from the [Contributor Covenant, version 1.2.0](http://contributor-covenant.org/version/1/2/0/).
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# How to contribute
|
|
2
|
+
|
|
3
|
+
Pull requests welcome! Please try to make them as complete and clear as possible, with reproduction steps and good tests.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Issues
|
|
7
|
+
|
|
8
|
+
Issues are monitored and responded to, but pull requests are much more likely to be merged.
|
|
9
|
+
|
|
10
|
+
Make sure the issue includes version information, reproduction steps, and any other relevant information.
|
|
11
|
+
|
|
12
|
+
You can use the `examples/sample_app.rb` to help reproduce the issue.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Pull Requests
|
|
16
|
+
|
|
17
|
+
All PRs with changes will be reviewed and merged if possible. Thank you for taking the time to contribute.
|
|
18
|
+
|
|
19
|
+
Changes must include tests. Please include a description of the problem and why the change is needed. Same with issues, reproduction steps are helpful.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Running the tests
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bundle install
|
|
26
|
+
bundle exec rake test
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
And running the linting with [standard](https://github.com/standardrb/standard):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bundle exec standardrb
|
|
33
|
+
```
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2011-2016 Sebastian Martinez
|
|
2
|
+
Copyright (c) 2005-2010 Jamis Buck
|
|
3
|
+
|
|
4
|
+
The MIT License (MIT)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
a copy of this software and associated documentation files (the
|
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be
|
|
15
|
+
included in all copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
# Exceptify
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/exceptify)
|
|
4
|
+
[](https://github.com/lukin-io/exceptify/actions/workflows/ci.yml)
|
|
5
|
+
|
|
6
|
+
Exceptify sends exception reports from Rails and Rack applications to the channels your team already watches: email, chat, webhooks, and monitoring tools.
|
|
7
|
+
|
|
8
|
+
This repository is maintained by [@lukin-io](https://github.com/lukin-io) as `lukin-io/exceptify` with the `exceptify` gem name and `Exceptify` API. Version `1.0.0` starts the maintained Exceptify release line.
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
Add the gem to your Rails application's `Gemfile`:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
gem "exceptify"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Install it and generate the initializer:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bundle install
|
|
22
|
+
bundle exec rails generate exceptify:install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Configure at least one notifier:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# config/initializers/exceptify.rb
|
|
29
|
+
require "exceptify/rails"
|
|
30
|
+
require "exceptify/rake"
|
|
31
|
+
|
|
32
|
+
Exceptify.configure do |config|
|
|
33
|
+
config.add_notifier :email, {
|
|
34
|
+
email_prefix: "[#{Rails.env.upcase}] ",
|
|
35
|
+
sender_address: %("Exceptify" <notifier@example.com>),
|
|
36
|
+
exception_recipients: %w[exceptions@example.com]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
config.ignore_if do |_exception, _options|
|
|
40
|
+
Rails.env.local?
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Email delivery uses your application's ActionMailer configuration. See [ActionMailer configuration](docs/notifiers/email.md#actionmailer-configuration) if emails do not send.
|
|
46
|
+
|
|
47
|
+
## How To Test It
|
|
48
|
+
|
|
49
|
+
After configuring a notifier, trigger a real exception in a non-production environment.
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# config/routes.rb
|
|
53
|
+
get "/exceptify_test", to: proc {
|
|
54
|
+
raise "Exceptify test"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Start Rails, visit `/exceptify_test`, and confirm the notification arrives. Remove the route after testing.
|
|
59
|
+
|
|
60
|
+
## Contents
|
|
61
|
+
|
|
62
|
+
* [Quick Start](#quick-start)
|
|
63
|
+
* [How To Test It](#how-to-test-it)
|
|
64
|
+
* [What It Does](#what-it-does)
|
|
65
|
+
* [Compatibility](#compatibility)
|
|
66
|
+
* [Installation](#installation)
|
|
67
|
+
* [Rails Setup](#rails-setup)
|
|
68
|
+
* [Common Workflows](#common-workflows)
|
|
69
|
+
* [Notifiers](#notifiers)
|
|
70
|
+
* [Noise Control](#noise-control)
|
|
71
|
+
* [Production Checklist](#production-checklist)
|
|
72
|
+
* [Background Jobs](#background-jobs)
|
|
73
|
+
* [Rack and Sinatra](#rack-and-sinatra)
|
|
74
|
+
* [Maintenance](#maintenance)
|
|
75
|
+
* [Development](#development)
|
|
76
|
+
* [License](#license)
|
|
77
|
+
|
|
78
|
+
## What It Does
|
|
79
|
+
|
|
80
|
+
Exceptify installs a Rack middleware that watches for unhandled exceptions during web requests and sends a notification with request, session, environment, backtrace, and optional application data.
|
|
81
|
+
|
|
82
|
+
Use it when you want a small, self-hosted notification layer for exceptions without adopting a hosted error tracker.
|
|
83
|
+
|
|
84
|
+
It supports:
|
|
85
|
+
|
|
86
|
+
* Rails integration through a generator and initializer.
|
|
87
|
+
* Rack middleware configuration for Rails, Sinatra, and other Rack apps.
|
|
88
|
+
* Built-in notifiers for email, Slack, Teams, Amazon SNS, Datadog, and webhooks.
|
|
89
|
+
* Manual reporting for rescued exceptions, background jobs, scripts, rake tasks, and runners.
|
|
90
|
+
* Ignore rules, crawler filtering, per-notifier filtering, and repeated-error grouping.
|
|
91
|
+
|
|
92
|
+
## Compatibility
|
|
93
|
+
|
|
94
|
+
* Exceptify 1.0.0 or newer.
|
|
95
|
+
* Ruby 3.4.4 or newer.
|
|
96
|
+
* Rails 8.0.2 or newer, below Rails 9.
|
|
97
|
+
* Rack applications, including Sinatra.
|
|
98
|
+
|
|
99
|
+
The changelog starts at `1.0.0` for the maintained `exceptify` release line.
|
|
100
|
+
|
|
101
|
+
## Installation
|
|
102
|
+
|
|
103
|
+
Add the gem to your application's `Gemfile`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
gem "exceptify"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Install it:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bundle install
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
To use this maintained repository directly from Git:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
gem "exceptify", git: "https://github.com/lukin-io/exceptify.git"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
For local gem development, point a test application at your checkout:
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
gem "exceptify", path: "../exceptify"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If the application should keep a Git source in its `Gemfile` while Bundler uses a local checkout, configure a local override from that application:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bundle config set local.exceptify ../exceptify
|
|
131
|
+
bundle install
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Rails Setup
|
|
135
|
+
|
|
136
|
+
Generate the Rails initializer:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
bundle exec rails generate exceptify:install
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The generated file is written to `config/initializers/exceptify.rb`.
|
|
143
|
+
|
|
144
|
+
Keep the gem available to every environment that loads the initializer. If you want notifications only in production, keep the gem outside a `production`-only bundle group and add an ignore rule for local environments.
|
|
145
|
+
|
|
146
|
+
### Initializer Notes
|
|
147
|
+
|
|
148
|
+
The generated initializer should load the Rails and Rake integrations, then register one or more notifiers. The email example in [Quick Start](#quick-start) is enough for a first setup; add other notifiers from [Notifiers](#notifiers) as needed.
|
|
149
|
+
|
|
150
|
+
### Rails Runner Support
|
|
151
|
+
|
|
152
|
+
If you want `rails runner` commands to report exceptions, load the Rails integration from `config/application.rb` below `Bundler.require`:
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
# config/application.rb
|
|
156
|
+
require "exceptify/rails"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The initializer is too late for runner callbacks. You can still keep notifier configuration in `config/initializers/exceptify.rb`.
|
|
160
|
+
The runner hook is guarded, so loading the integration more than once does not install duplicate `at_exit` callbacks.
|
|
161
|
+
|
|
162
|
+
## Common Workflows
|
|
163
|
+
|
|
164
|
+
### Send to Email and Slack
|
|
165
|
+
|
|
166
|
+
Slack notifications require the `slack-notifier` gem:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
gem "slack-notifier"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Then register both notifiers:
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
Exceptify.configure do |config|
|
|
176
|
+
config.add_notifier :email, {
|
|
177
|
+
email_prefix: "[#{Rails.env.upcase}] ",
|
|
178
|
+
sender_address: %("Exceptify" <notifier@example.com>),
|
|
179
|
+
exception_recipients: %w[exceptions@example.com]
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (webhook_url = Rails.application.credentials.dig(:slack, :exceptions_webhook_url))
|
|
183
|
+
config.add_notifier :slack, {
|
|
184
|
+
webhook_url: webhook_url,
|
|
185
|
+
channel: "#exceptions",
|
|
186
|
+
additional_parameters: {
|
|
187
|
+
mrkdwn: true
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Attach Request Context
|
|
195
|
+
|
|
196
|
+
Store application data in the request environment before an exception is raised:
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
class ApplicationController < ActionController::Base
|
|
200
|
+
before_action :prepare_exceptify_notification
|
|
201
|
+
|
|
202
|
+
private
|
|
203
|
+
|
|
204
|
+
def prepare_exceptify_notification
|
|
205
|
+
request.env["exceptify.exception_data"] = {
|
|
206
|
+
current_user_id: current_user&.id,
|
|
207
|
+
account_id: current_account&.id,
|
|
208
|
+
request_id: request.request_id
|
|
209
|
+
}
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
That data is included in supported notifier payloads and email sections.
|
|
215
|
+
|
|
216
|
+
### Report a Handled Controller Error
|
|
217
|
+
|
|
218
|
+
Middleware only sees exceptions that continue up the Rack stack. If a controller rescues an error, notify manually:
|
|
219
|
+
|
|
220
|
+
```ruby
|
|
221
|
+
class OrdersController < ApplicationController
|
|
222
|
+
rescue_from PaymentGateway::Timeout, with: :payment_gateway_timeout
|
|
223
|
+
|
|
224
|
+
private
|
|
225
|
+
|
|
226
|
+
def payment_gateway_timeout(exception)
|
|
227
|
+
Exceptify.notify_exception(
|
|
228
|
+
exception,
|
|
229
|
+
env: request.env,
|
|
230
|
+
data: {
|
|
231
|
+
order_id: params[:id],
|
|
232
|
+
request_id: request.request_id
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
render json: {error: "payment_gateway_timeout"}, status: :bad_gateway
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Report from Plain Ruby Code
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
begin
|
|
245
|
+
ImportCustomers.call(file_path)
|
|
246
|
+
rescue => exception
|
|
247
|
+
Exceptify.notify_exception(
|
|
248
|
+
exception,
|
|
249
|
+
data: {
|
|
250
|
+
job: "ImportCustomers",
|
|
251
|
+
file_path: file_path
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
raise
|
|
256
|
+
end
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Filter Sensitive Parameters
|
|
260
|
+
|
|
261
|
+
Exception emails can include request parameters. Use Rails parameter filtering for secrets:
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
# config/application.rb
|
|
265
|
+
config.filter_parameters += [
|
|
266
|
+
:password,
|
|
267
|
+
:password_confirmation,
|
|
268
|
+
:credit_card_number,
|
|
269
|
+
:secret_details
|
|
270
|
+
]
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Notifiers
|
|
274
|
+
|
|
275
|
+
Built-in notifier docs and support status:
|
|
276
|
+
|
|
277
|
+
| Notifier | Status | Docs |
|
|
278
|
+
| --- | --- | --- |
|
|
279
|
+
| Email | Supported | [Email](docs/notifiers/email.md) |
|
|
280
|
+
| Slack | Supported | [Slack](docs/notifiers/slack.md) |
|
|
281
|
+
| Teams | Supported | [Teams](docs/notifiers/teams.md) |
|
|
282
|
+
| Amazon SNS | Supported | [Amazon SNS](docs/notifiers/sns.md) |
|
|
283
|
+
| Datadog | Supported | [Datadog](docs/notifiers/datadog.md) |
|
|
284
|
+
| WebHook | Supported | [WebHook](docs/notifiers/webhook.md) |
|
|
285
|
+
| Custom notifiers | Supported extension point | [Custom notifiers](docs/notifiers/custom.md) |
|
|
286
|
+
|
|
287
|
+
### Notifier Setup Rules
|
|
288
|
+
|
|
289
|
+
Network notifiers validate required options during setup. Missing `webhook_url`, `url`, or AWS credentials raise `ArgumentError` instead of silently disabling notifications.
|
|
290
|
+
|
|
291
|
+
For tests, custom transports, or apps that already wrap provider clients, pass an injected client:
|
|
292
|
+
|
|
293
|
+
```ruby
|
|
294
|
+
Exceptify.configure do |config|
|
|
295
|
+
config.add_notifier :webhook, {
|
|
296
|
+
url: "https://example.com/exception-webhook",
|
|
297
|
+
http_client: MyHTTPClient
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
config.add_notifier :sns, {
|
|
301
|
+
topic_arn: "arn:aws:sns:us-east-1:123456789012:exceptions",
|
|
302
|
+
client: Aws::SNS::Client.new(region: "us-east-1")
|
|
303
|
+
}
|
|
304
|
+
end
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Slack accepts `notifier:` for a prebuilt Slack client. Use `fail_silently: true` only as a temporary compatibility option while migrating old silent configurations.
|
|
308
|
+
|
|
309
|
+
You can also register any object that responds to `#call(exception, options)`:
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
Exceptify.configure do |config|
|
|
313
|
+
config.add_notifier :logger, lambda { |exception, options|
|
|
314
|
+
Rails.logger.error(
|
|
315
|
+
"[exceptify] #{exception.class}: #{exception.message} #{options[:data].inspect}"
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
end
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Noise Control
|
|
322
|
+
|
|
323
|
+
### Ignore Known Exceptions
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
Exceptify.configure do |config|
|
|
327
|
+
config.ignored_exceptions += %w[
|
|
328
|
+
ActionView::TemplateError
|
|
329
|
+
MyApp::ExpectedError
|
|
330
|
+
]
|
|
331
|
+
end
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The default ignored exceptions include common routing, record-not-found, and invalid-parameter errors.
|
|
335
|
+
|
|
336
|
+
### Ignore Crawlers
|
|
337
|
+
|
|
338
|
+
```ruby
|
|
339
|
+
Exceptify.configure do |config|
|
|
340
|
+
config.ignore_crawlers %w[Googlebot bingbot]
|
|
341
|
+
end
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Ignore by Condition
|
|
345
|
+
|
|
346
|
+
```ruby
|
|
347
|
+
Exceptify.configure do |config|
|
|
348
|
+
config.ignore_if do |exception, options|
|
|
349
|
+
path = options.dig(:env, "PATH_INFO")
|
|
350
|
+
|
|
351
|
+
Rails.env.local? ||
|
|
352
|
+
path == "/health" ||
|
|
353
|
+
exception.message.match?(/Couldn't find Page with ID=/)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Ignore Only One Notifier
|
|
359
|
+
|
|
360
|
+
Use per-notifier filtering when email should still send but chat should stay quiet, or the reverse:
|
|
361
|
+
|
|
362
|
+
```ruby
|
|
363
|
+
Exceptify.configure do |config|
|
|
364
|
+
config.ignore_notifier_if(:slack) do |exception, _options|
|
|
365
|
+
exception.is_a?(ActionController::RoutingError)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Group Repeated Errors
|
|
371
|
+
|
|
372
|
+
Error grouping prevents notification floods for the same exception. With the default trigger, notifications are sent at counts 1, 2, 4, 8, 16, and so on.
|
|
373
|
+
|
|
374
|
+
```ruby
|
|
375
|
+
Exceptify.configure do |config|
|
|
376
|
+
config.error_grouping = true
|
|
377
|
+
config.error_grouping_cache = Rails.cache
|
|
378
|
+
config.error_grouping_period = 5.minutes
|
|
379
|
+
|
|
380
|
+
config.notification_trigger = lambda { |_exception, count|
|
|
381
|
+
count == 1 || (count % 10).zero?
|
|
382
|
+
}
|
|
383
|
+
end
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Production Checklist
|
|
387
|
+
|
|
388
|
+
Before relying on exception notifications in production:
|
|
389
|
+
|
|
390
|
+
* Configure at least one notifier.
|
|
391
|
+
* Verify delivery with a real test exception in staging.
|
|
392
|
+
* Confirm ActionMailer delivery settings if using email.
|
|
393
|
+
* Filter secrets with `config.filter_parameters`.
|
|
394
|
+
* Ignore local and test environments.
|
|
395
|
+
* Add crawler or health-check ignores if they create noise.
|
|
396
|
+
* Enable error grouping for high-traffic applications.
|
|
397
|
+
* Make sure background jobs are covered separately from web requests.
|
|
398
|
+
|
|
399
|
+
## Background Jobs
|
|
400
|
+
|
|
401
|
+
The Rack middleware only catches exceptions during web requests. For jobs and command-line work, use one of the integrations below.
|
|
402
|
+
|
|
403
|
+
### Rake Tasks
|
|
404
|
+
|
|
405
|
+
The generated initializer includes:
|
|
406
|
+
|
|
407
|
+
```ruby
|
|
408
|
+
require "exceptify/rake"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
That reports unhandled exceptions from rake tasks.
|
|
412
|
+
|
|
413
|
+
### Rails Runner
|
|
414
|
+
|
|
415
|
+
For `rails runner`, require the Rails integration from `config/application.rb` as shown in [Rails Runner Support](#rails-runner-support).
|
|
416
|
+
|
|
417
|
+
### Sidekiq, Resque, and Solid Queue
|
|
418
|
+
|
|
419
|
+
Generate an initializer with the integration you need:
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
bundle exec rails generate exceptify:install --sidekiq
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
or:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
bundle exec rails generate exceptify:install --resque
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
or:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
bundle exec rails generate exceptify:install --solid-queue
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
The Solid Queue integration hooks into Active Job failure notifications and reports unhandled exceptions for jobs using the `solid_queue` adapter. It preserves Active Job failure behavior, so failed jobs still end up in Solid Queue's failed executions table and `retry_on` or `discard_on` handlers still run normally.
|
|
438
|
+
|
|
439
|
+
### Manual Job Reporting
|
|
440
|
+
|
|
441
|
+
If a job system is not integrated, report exceptions directly:
|
|
442
|
+
|
|
443
|
+
```ruby
|
|
444
|
+
class RebuildSearchIndexJob
|
|
445
|
+
def perform(account_id)
|
|
446
|
+
RebuildSearchIndex.call(account_id)
|
|
447
|
+
rescue => exception
|
|
448
|
+
Exceptify.notify_exception(
|
|
449
|
+
exception,
|
|
450
|
+
data: {
|
|
451
|
+
job: self.class.name,
|
|
452
|
+
account_id: account_id
|
|
453
|
+
}
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
raise
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Rack and Sinatra
|
|
462
|
+
|
|
463
|
+
Use the Rack middleware directly when you are not using the Rails generator, or when you need Rack-only options such as `ignore_cascade_pass`.
|
|
464
|
+
|
|
465
|
+
```ruby
|
|
466
|
+
require "exceptify"
|
|
467
|
+
|
|
468
|
+
use Exceptify::Rack,
|
|
469
|
+
email: {
|
|
470
|
+
email_prefix: "[RACK ERROR] ",
|
|
471
|
+
sender_address: %("Exceptify" <notifier@example.com>),
|
|
472
|
+
exception_recipients: %w[exceptions@example.com]
|
|
473
|
+
},
|
|
474
|
+
ignore_exceptions: ["Sinatra::NotFound"],
|
|
475
|
+
ignore_cascade_pass: true
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Options passed directly to `Exceptify::Rack` are local to that middleware instance. To use one application-wide configuration, configure `Exceptify` once and mount the middleware without notifier options:
|
|
479
|
+
|
|
480
|
+
```ruby
|
|
481
|
+
require "exceptify"
|
|
482
|
+
|
|
483
|
+
Exceptify.configure do |config|
|
|
484
|
+
config.add_notifier :email, {
|
|
485
|
+
sender_address: %("Exceptify" <notifier@example.com>),
|
|
486
|
+
exception_recipients: %w[exceptions@example.com]
|
|
487
|
+
}
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
use Exceptify::Rack
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Sinatra users can also review the [example application](examples/sinatra).
|
|
494
|
+
|
|
495
|
+
## Maintenance
|
|
496
|
+
|
|
497
|
+
This repository is the current home for the `exceptify` gem. Maintenance focuses on modern Ruby and Rails support, clear documentation, and practical bug fixes around the `Exceptify` API.
|
|
498
|
+
|
|
499
|
+
Issues and pull requests are welcome when they include enough context to reproduce the behavior.
|
|
500
|
+
The current refactoring direction is tracked in [REFACTORING.md](REFACTORING.md).
|
|
501
|
+
|
|
502
|
+
## Development
|
|
503
|
+
|
|
504
|
+
Install dependencies:
|
|
505
|
+
|
|
506
|
+
```bash
|
|
507
|
+
bundle install
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Run tests:
|
|
511
|
+
|
|
512
|
+
```bash
|
|
513
|
+
bundle exec rake test
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Open a console with the gem loaded:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
bundle exec rake console
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Build the gem locally:
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
bundle exec rake build
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Pull requests and issues are welcome. Please read the [Contributing Guide](CONTRIBUTING.md) and follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
529
|
+
|
|
530
|
+
## License
|
|
531
|
+
|
|
532
|
+
Released under the [MIT license](MIT-LICENSE).
|
|
533
|
+
|
|
534
|
+
Maintainer: [@lukin-io](https://github.com/lukin-io)
|
data/RELEASING.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Releasing Exceptify
|
|
2
|
+
|
|
3
|
+
## First RubyGems.org Publish
|
|
4
|
+
|
|
5
|
+
The `exceptify` gem is built from `exceptify.gemspec`. RubyGems.org receives the
|
|
6
|
+
built `.gem` file, not the Git repository.
|
|
7
|
+
|
|
8
|
+
Run the first publish manually:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
bundle install
|
|
12
|
+
bundle exec rake test
|
|
13
|
+
bundle exec standardrb
|
|
14
|
+
gem build --strict exceptify.gemspec
|
|
15
|
+
gem signin
|
|
16
|
+
gem push exceptify-1.0.0.gem
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
RubyGems.org versions are immutable. If a pushed gem needs any code or metadata
|
|
20
|
+
change, bump `Exceptify::VERSION` and publish a new version.
|
|
21
|
+
|
|
22
|
+
## Trusted Publishing Setup
|
|
23
|
+
|
|
24
|
+
After the first publish, configure RubyGems.org Trusted Publishing for automated
|
|
25
|
+
tag releases:
|
|
26
|
+
|
|
27
|
+
- Gem name: `exceptify`
|
|
28
|
+
- GitHub repository owner: `lukin-io`
|
|
29
|
+
- GitHub repository name: `exceptify`
|
|
30
|
+
- Workflow filename: `gem-push.yml`
|
|
31
|
+
- Environment: `release`
|
|
32
|
+
|
|
33
|
+
The workflow publishes tagged releases to both GitHub Packages and RubyGems.org.
|
|
34
|
+
RubyGems.org publishing uses GitHub OIDC through `rubygems/release-gem@v1`, so no
|
|
35
|
+
long-lived `RUBYGEMS_AUTH_TOKEN` secret is needed.
|
|
36
|
+
|
|
37
|
+
## Release Flow
|
|
38
|
+
|
|
39
|
+
1. Update `Exceptify::VERSION` in `lib/exceptify/version.rb`.
|
|
40
|
+
2. Update `CHANGELOG.rdoc`.
|
|
41
|
+
3. Commit the changes.
|
|
42
|
+
4. Create a matching tag:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
git tag v1.0.0
|
|
46
|
+
git push origin main
|
|
47
|
+
git push origin v1.0.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The CI workflow verifies that the tag name matches the gem version before
|
|
51
|
+
publishing.
|