Server-side Fingerprinting

Server-side fingerprinting is also configured with a config similar to grouping enhancements, but the syntax is slightly different. The matchers are the same but instead of flipping flags, a fingerprint is assigned that overrides the default grouping entirely.

These rules can be configured on a per-project basis under Project Settings > General Settings > Grouping Settings. You are presented with an input field where you can write custom fingerprinting rules. The syntax follows the syntax from Discover queries. If you want to negate the match, you can prefix the expression with an exclamation mark (!).

All values are matched against, and in the case of stack traces, all frames are considered. If all matches in a line match, then the fingerprint is applied.

Copied
# You can use comments to explain the rules.  Rules themselves follow the
# following syntax:
matcher:expression -> list, of, values

This list of values can be hardcoded values or alternatively some variables whch are substituded.

This is a practical example, which groups exceptions of a specific type together:

Copied
error.type:DatabaseUnavailable -> system-down
error.type:ConnectionError -> system-down

error.value:"connection error: *" -> connection-error, {{ transaction }}

Matchers

All values are matched against, and in the case of stack traces, all frames are considered. If all matches in a line match, then the fingerprint is applied. The syntax follows the syntax from Discover queries. If you want to negate the match, you can prefix the expression with an exclamation mark (!).

Matchers generally use globbing syntax. The following matchers are available:

error.type

alias: type

Matches on an exception type (exception name). The match is performed as a case sensitive glob.

Copied
error.type:ZeroDivisionError -> zero-division
error.type:ConnectionError -> connection-error

error.value

alias: value

Matches on the exception value. Errors or exceptions often have human readable descriptions (values) associated with them. This matcher allows a case insensitive match.

Copied
error.value:"connection error (code: *)" -> connection-error
error.value:"could not connect (*)" -> connection-error

message

This matcher matches on a log message. It will also automatically check for the additional exception value as they can be hard to keep apart. The matching is done case insensitive.

Copied
message:"system encountered a fatal problem: *" -> fatal-log

logger

Matches on the name of the logger, which is useful to combine all messages of a logger together. This match is case sensitive.

Copied
logger:"com.myapp.mypackage.*" -> mypackage-logger

level

Matches on the log level. The match is case insensitive.

Copied
logger:"com.myapp.FooLogger" level:"error" -> mylogger-error

tags.tag_name

Matches on the value of the tag tag_name. This can be useful to filter down certain types of events. For instance, you can separate out events caused by a certain server:

Copied
tags.server_name:"canary-*.mycompany.internal" -> canary-events

stack.abs_path

alias: path

This matcher is case insensitive matching on the path of an event. It uses path globbing semantics which means that * does not match a slash but ** does. Note that this matcher actually matches on both abs_path and filename as SDKs can be quite inconsistent about how these values are supported. If the glob matches on either of these values it's considered a match.

Copied
stack.abs_path:"**/my-utils/*.js" -> my-utils, {{ error.type }}

stack.module

alias: module

This matcher is similar to stack.abs_path but matches on the module name instead. The match is case sensitive and regular globbing rules apply (* also matches slashes).

Copied
stack.module:"*/my-utils/*" -> my-utils, {{ error.type }}

stack.function

alias: function

This matcher checks if any of the functions in the stack trace match the glob. The match is case sensitive:

Copied
stack.function:"my_assertion_failed" -> my-assertion-failed

stack.package

alias: package

This matcher matches on the "package" of a frame. This is typically the name of the debug symbol / object file that contains a frame. If any of the frames match this object file then it matches.

Copied
stack.package:"**/libcurl.dylib" -> libcurl
stack.package:"**/libcurl.so" -> libcurl

family

This matcher can be used to "scope" down the matcher. The following families exist: javascript for any type of javascript event, native for any type of native event. Any other platform is called other.

Copied
family:native !stack.module:"myproject::*" -> not-from-my-project

app

This matcher checks if the frame is in app or not. This is particularly useful when combined with another matcher. Possible values are yes and no:

Copied
app:yes stack.function:"assert" -> assert

Combining Matchers

When multiple matchers are combined, they all need to match. Matchers that operate on frames must all apply to the same frame otherwise they are not considered to match. For instance, if you match on both function name and module name then a match only exists if a frame matches both the function name and the module name. It's not enough for a frame to match only with the function name, even if another frame would match the module name by itself. matching function name only even if there is another frame that would match the module name by itself.

Copied
# this matches if a frame exists with a specific function and module name
# and also a specific error type is thrown
error.type:ConnectionError stack.function:"connect" stack.module:"bot" -> bot-error

Variables

On the right hand side of the fingerprint constant values as well as variables can be used. Variables are substituded automatically. Variables have the same name as matchers but they might be filled in differently.

Variables are enclosed in double braces ({{ variable_name }}).

{{ default }}

This fills in the default fingerprint that would be produced by the normal grouping operation. This is useful if you want to subdivide an already existing group by something else:

Copied
stack.function:"query_database" -> {{ default }}, {{ transaction }}

{{ transaction }}

This fills in the name of the transaction into the fingerprint. This will force the creation of a group per transaction:

Copied
error.type:"ApiError" -> api-error, {{ transaction }}

{{ error.type }}

alias: {{ type }}

This fills in the name of the error that ocurred. When chained exceptions are used this will be the most recently thrown error. This will force the creation of a group per transaction:

Copied
stack.function:"evaluate_script" -> script-evaluation, {{ error.type }}

{{ stack.function }}

alias: {{ function }}

This fills in the function name of the "crashing frame". That is the top most frame that was considered to be in the application code.

Copied
error.type:"ScriptError" -> script-evaluation, {{ stack.function }}

{{ stack.module }}

alias: {{ module }}

This fills in the module name of the "crashing frame". That is the top most frame that was considered to be in the application code.

Copied
error.type:"ScriptError" -> script-evaluation, {{ stack.module }}

{{ stack.package }}

alias: {{ package }}

This fills in the package name (object file) of the "crashing frame". That is the top most frame that was considered to be in the application code.

Copied
stack.function:"assert" -> assertion, {{ stack.package }}

{{ logger }}

This fills in the name of the logger that caused an event.

Copied
message:"critical connection error*" -> connection-error, {{ logger }}

{{ level }}

This fills in the name of the log level that was used to create an event.

Copied
message:"connection error*" -> connection-error, {{ logger }}, {{ level }}

{{ tags.tag_name }}

This fills in the value of a tag into the fingerprint, which can, for instance, be used to split events by server name or something similar.

Copied
message:"connection error*" -> connection-error, {{ tags.server_name }}
You can edit this page on GitHub.
Package:
github:getsentry/sentry-native
Version:
0.4.2
Repository:
https://github.com/getsentry/sentry-native