Event Breadcrumbs
Any Magic event that implements ReportsBreadcrumb becomes a Sentry breadcrumb, with no extra wiring.
On this page
Quick Reference#
Make the event opt in; the provider's wildcard listener does the rest:
import 'package:magic/magic.dart';
class InvoicePaid extends MagicEvent implements ReportsBreadcrumb {
InvoicePaid(this.invoiceId);
final String invoiceId;
@override
String get breadcrumbCategory => 'billing';
@override
String get breadcrumbMessage => 'Invoice paid';
@override
Map<String, Object?> get breadcrumbData => {'invoice_id': invoiceId};
}
Dispatching InvoicePaid adds an info breadcrumb with that category, message and data to the next event Sentry sends.
How It Works#
SentryServiceProvider.boot() registers one listener through Event.listenAny, which runs on every dispatch. For each event it asks EventBreadcrumbs.breadcrumbFor, which answers null unless the event implements ReportsBreadcrumb, and adds what it returns with Sentry.addBreadcrumb. This package does not know which events exist; the event opts in.
A second boot() in the same isolate removes the previous listener before adding one, so a test suite that boots the provider again does not register it twice. magic_deeplink's DeeplinkOpened and DeeplinkNavigating already implement the contract: DeeplinkOpened carries the matched route pattern, the link's source and a names-tenant flag, and DeeplinkNavigating carries the route pattern only, never the path or the query.
What Goes in the Data#
breadcrumbData is a whitelist the event author curates. breadcrumbFor copies it as it is and never adds or drops a key. The breadcrumb also passes through SentryTokenScrubber.beforeBreadcrumb, which masks tokens that look like tokens, but that is a net and not a licence: keep tokens, emails and query values out of the map.
Gotchas#
| Mistake | Fix |
|---|---|
Expecting a plain MagicEvent to leave a breadcrumb |
Add implements ReportsBreadcrumb; events that do not opt in are skipped |
Putting a secret in breadcrumbData |
It is sent as written apart from token masking; whitelist only what is safe to store |
| Expecting a breadcrumb without a DSN | boot() returns early when Sentry.isEnabled is false, so no listener is registered |
Related Documentation#
- Boot and the Provider: where the listener is registered.
- Token Scrubbing: the masking a breadcrumb passes through.