Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Please see the [doc](doc) folder for further documentation on:
* [Understanding the request lifecycle](doc/request-lifecycle.md)
* [Exceptions raised by Rack::Timeout](doc/exceptions.md)
* [Rollbar fingerprinting](doc/rollbar.md)
* [Sentry fingerprinting](doc/sentry.md)
* [Observers](doc/observers.md)
* [Settings](doc/settings.md)
* [Logging](doc/logging.md)
Expand Down
29 changes: 29 additions & 0 deletions doc/sentry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### Sentry

Because rack-timeout may raise at any point in the codepath of a timed-out request, the stack traces for similar requests may differ, causing Sentry to create separate issues for each timeout.

The recommended practice is to configure a custom [fingerprint][sentry-fingerprinting] in your `before_send` hook, grouping timeouts by the transaction (controller#action) instead of by stack trace. Prepending the route to the exception message also gives each issue a readable, route-led title.

[sentry-fingerprinting]: https://docs.sentry.io/platforms/ruby/usage/sdk-fingerprinting/

Example:

```ruby
Sentry.init do |config|
config.before_send = lambda do |event, hint|
exception = hint[:exception]
timeout = exception.is_a?(Rack::Timeout::RequestTimeoutException) ||
exception.is_a?(Rack::Timeout::Error)
if timeout && event.transaction.present?
event.fingerprint = [exception.class.name, event.transaction]
timeout_exception = event.exception.values.last
timeout_exception.value = "#{event.transaction} — #{timeout_exception.value}"
end
event
end
end
```

This groups timeouts by route and titles each issue `Rack::Timeout::RequestTimeoutException: controller#action — Request ran for longer than 15000ms` — the route leads (the Sentry analogue of the Rollbar `title` recipe) while rack-timeout's original wait/timeout detail is preserved rather than discarded.

`RequestTimeoutException` is raised into the application thread; if it bubbles past your middleware it is re-raised as `RequestTimeoutError` (see [doc/exceptions](exceptions.md)). Matching `RequestTimeoutException` and the `Rack::Timeout::Error` base (which covers `RequestTimeoutError` and `RequestExpiryError`) means timeouts group by route regardless of where Sentry's capture middleware sits in the stack. The `event.transaction.present?` guard leaves timeouts raised before controller dispatch (no transaction) on Sentry's default grouping, rather than blanking the title.