Issues & grouping
An issue is one bug. Events are its occurrences. The rule we optimise for: never split one bug into many issues.
How grouping works
Each event gets one or more hashes. It joins an existing issue if any of its hashes matches. In priority order:
- Custom fingerprint, if the SDK sent one. It replaces default grouping.
- Stack shape: the frames of the last exception (plus its chain). In-app frames only, falling back to all frames if none are in-app. Each frame is module + lowercased file basename + normalized function. Line and column numbers are never used, so a deploy that shifts lines does not create new issues. Recursion is collapsed. The exception type is prefixed.
- Type + value: exception type plus the first line of the message with variable parts (emails, URLs, UUIDs, hex ids, dates, IPs, numbers, quoted strings) replaced by placeholders. This is also stored as a second hash on every exception event, so a refactor that changes the stack still lands in the same issue.
- Message: the first line of the parameterized log message, when there is no exception.
Titles keep the original text. The issue page has a Grouping panel that shows each hash and where it came from.
Custom fingerprints
Set fingerprint in the SDK. {{ default }} expands to the default stack hash, so you can split one issue by something extra:
Sentry.captureException(err, {
fingerprint: ["{{ default }}", tenant.region],
});
A fingerprint of only ["{{ default }}"] is the same as sending none.
In-app rules
Rules decide which frames are your code. They override the SDK. Syntax is the Sentry/Bugsink one, one rule per line, later lines win:
matcher:glob [+app|-app] [-group]
Matchers are stack.abs_path, stack.module and stack.function. Built in:
stack.abs_path:**/node_modules/** -app
stack.abs_path:node:* -app
stack.abs_path:internal/** -app
stack.abs_path:**/webpack/runtime/** -app
stack.abs_path:**/gems/** -app
stack.abs_path:/usr/lib/ruby/** -app
stack.abs_path:**/vendor/bundle/** -app
stack.module:sentry* -app -group
stack.module:@sentry/** -app -group
stack.abs_path:**/@sentry/** -app -group
stack.abs_path:**/gems/sentry-*/** -app -group
stack.function:sentry* -app -group
-group means the frame is left out of the stack hash. Add your own per project in Settings → Projects, for example stack.abs_path:**/node_modules/@acme/** +app.
What gets stored
Counters always count every event. Full events are stored by exception: per issue, the first 25 events of each hour, then 1 in 20, and always one from a release or user the issue has not seen yet. Events are kept for 90 days by default, set per project.
Resolve
- Resolve: closes the issue. Any new event reopens it as a regression.
- Resolve in release X: events from releases that sort before X do not reopen it. Events from X or later do. Releases sort by semver when they parse, otherwise by when they were first seen.
- Resolve in next release: the same, for the next release OpenFault sees. See the README for current behaviour; this is still being finished.
A regression reopens the issue, records it in the activity log and sends a regression notification.
Mute
Mute until a time, until a volume (N events within M minutes), or both. When either is reached the issue unmutes and sends an unmute notification. Unmute by hand any time.
Search
is:unresolved level:error release:1.2 env:prod assignee:me approved:yes "free text"
Sort by last seen, first seen, events or users.