Filtering

When you add Sentry to your app, you get a lot of valuable information about errors and performance. And lots of information is good -- as long as it's the right information, at a reasonable volume.

The Sentry SDKs have several configuration options to help you filter out events.

We also offer Inbound Filters to filter events in sentry.io. We recommend filtering at the client level though, because it removes the overhead of sending events you don't actually want. Learn more about the fields available in an event.

Configure your SDK to filter error events by using the before_send callback method and configuring, enabling, or disabling integrations.

All Sentry SDKs support the before_send callback method. Because it's called immediately before the event is sent to the server, this is your last chance to decide not to send data or to edit it. before_send receives the event object as a parameter, which you can use to either modify the event’s data or drop it completely by returning null, based on custom logic and the data available on the event.

Copied
#include <sentry.h>

sentry_value_t strip_sensitive_data(sentry_value_t event, void *hint) {
  /* modify event here or return NULL to discard the event */
  return event;
}

int main(void) {
  sentry_options_t *options = sentry_options_new();
  sentry_options_set_before_send(options, strip_sensitive_data, NULL);
  sentry_init(options);

  /* ... */
}

The callback is executed in the same thread as the call to sentry_capture_event. Work performed by the function may thus block the executing thread. For this reason, consider avoiding heavy work in before_send.

The before_send callback implementation in sentry-native makes it hard to distinguish between normal events and crashes. For this reason, we introduced another callback, on_crash, which - at this point - only exists in sentry_native:

Copied
#include <sentry.h>

static sentry_value_t
crash_cleanup(
    const sentry_ucontext_t *uctx, // provides the user-space context of the crash
    sentry_value_t event,          // used the same way as in `before_send`
    void *closure                  // user-data that you can provide at configuration time
)
{
    // Do contextual clean-up before the crash is sent to sentry's backend infrastructure

    /* ... */

    // tell the backend to retain the event (+ dump)
    // or to discard it, you could free the event and return a `null`:
    //       sentry_value_decref(event);
    //       return sentry_value_new_null();
    return event;
}

int main(void) {
  sentry_options_t *options = sentry_options_new();
  sentry_options_set_on_crash(options, crash_cleanup, NULL);
  sentry_init(options);

  /* ... */
}

The on_crash callback replaces before_send as a callback for crash events only. They can be defined simultaneously, where the SDK prevents before_send from being invoked for crash events. This allows for better differentiation between crashes and other events and gradual migration from existing before_send implementations:

  • If you have a before_send implementation and do not define an on_crash callback before_send will receive both normal and crash events as before
  • If you only want to pre-process normal events with before_send, then you can define an "empty" on_crash callback that returns the passed-in event and does nothing else.
  • If you are not interested in pre-processing normal events but only want to act on crashes, then only define an on_crash callback with the option to filter (available for all backends) or enrich (only for inproc) the crash event.

Note also that breadcrumbs can be filtered, as discussed in our Breadcrumbs documentation.

The before_send callback is passed both the event and a second argument, hint, that holds one or more hints.

Typically, a hint holds the original exception so that additional data can be extracted or grouping is affected. In this example, the fingerprint is forced to a common value if an exception of a certain type has been caught:

Copied
#include <string.h>
#include <sentry.h>

sentry_value_t before_send(sentry_value_t event, void *hint) {
  /* sentry_value_t functions handle NULL automatically */
  sentry_value_t exceptions = sentry_value_get_by_key(event, "exception");
  sentry_value_t values = sentry_value_get_by_key(exceptions, "values");
  sentry_value_t exception = sentry_value_get_by_index(values, 0);
  sentry_value_t type = sentry_value_get_by_key(exception, "type");
  const char *type_str = sentry_value_as_string(type);

  /* use the data passed during initialization */
  const char *custom_error = (const char *)hint;

  if (type_str && strcmp(type_str, custom_error) == 0) {
    sentry_value_t fingerprint = sentry_value_new_list();
    sentry_value_append(fingerprint, sentry_value_new_string("custom-error"));
    sentry_value_set_by_key(event, "fingerprint", fingerprint);
  }

  return event;
}

int main(void) {
  sentry_options_t *options = sentry_options_new();
  sentry_options_set_before_send(options, before_send, (void *)"CustomError");
  sentry_init(options);

  /* ... */
}

When the SDK creates an event or breadcrumb for transmission, that transmission is typically created from some sort of source object. For instance, an error event is typically created from a log record or exception instance. For better customization, SDKs send these objects to certain callbacks (before_send, before_breadcrumb or the event processor system in the SDK).

Help improve this content
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").