SDK Fingerprinting
Learn about overriding default fingerprinting in your SDK.
All events have a fingerprint. Events with the same fingerprint are grouped together into an issue.
By default, Sentry will run one of our built-in grouping algorithms to generate a fingerprint based on information available within the event such as stacktrace
, exception
, and message
. To extend the default grouping behavior or change it completely, you can use a combination of the following options:
- In your SDK, using SDK Fingerprinting, as documented below
- In your project, using Fingerprint Rules or Stack Trace Rules
In supported SDKs, you can override Sentry's default grouping that passes the fingerprint attribute as an array of strings. The length of a fingerprint's array is not restricted. This works similarly to the fingerprint rules functionality, which is always available and can achieve similar results.
In the most basic case, values are passed directly:
FutureOr<SentryEvent?> beforeSend(SentryEvent event, Hint hint) async {
if (event.throwable is DatabaseException) {
event = event.copyWith(fingerprint: ['database-connection-error']);
}
return event;
}
await SentryFlutter.init((options) => options.beforeSend = beforeSend);
You can use variable substitution to fill dynamic values into the fingerprint generally computed on the server. For instance, the value {{ default }}
can be added to add the entire normally generated grouping hash into the fingerprint. These values are the same as for server-side fingerprinting. See Variables for more information.
In some scenarios, you'll want to group errors more granularly.
For example, if your application queries a Remote Procedure Call Model (RPC) interface or external Application Programming Interface (API) service, the stack trace is generally the same, even if the outgoing request is very different.
The following example will split up the default group Sentry would create (represented by {{ default }}
) further, taking some attributes on the error object into account:
class MyRpcException implements Exception {
final String function;
final int httpStatusCode;
MyRpcException(this.function, this.httpStatusCode);
}
FutureOr<SentryEvent?> beforeSend(SentryEvent event, Hint hint) async {
if (event.throwable is MyRpcException) {
final exception = event.throwable as MyRpcException;
event = event.copyWith(fingerprint: [
'{{ default }}',
exception.function,
exception.httpStatusCode.toString(),
]);
}
return event;
}
await SentryFlutter.init((options) => options.beforeSend = beforeSend);
You can also overwrite Sentry's grouping entirely.
For example, if a generic error, such as a database connection error, has many different stack traces and never groups them together, you can overwrite Sentry's grouping by omitting {{ default }}
from the array:
FutureOr<SentryEvent?> beforeSend(SentryEvent event, Hint hint) async {
if (event.throwable is DatabaseException) {
event = event.copyWith(fingerprint: ['database-connection-error']);
}
return event;
}
await SentryFlutter.init((options) => options.beforeSend = beforeSend);
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").