From d346db6c20577b2f30d4c6d5c1b2f9eb1a0f3d5b Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Thu, 25 Jun 2026 15:36:27 +0200 Subject: [PATCH 01/14] docs(dart): Add New Spans and migration guide for span streaming Document stream mode (SentryTraceLifecycle.stream) for the Dart and Flutter SDKs, where spans are sent as they finish instead of being batched into a transaction. Mirrors the Python New Spans pages. - New Spans page: enabling stream mode, manual instrumentation with startSpan/startSpanSync/startInactiveSpan, typed attributes, status, beforeSendSpan/ignoreSpans, sampling, and verification - Migration guide: mapping transaction-based APIs to the new span APIs - Platform-includes split init snippets for Flutter vs plain Dart Co-Authored-By: Claude --- .../dart/common/tracing/new-spans/index.mdx | 230 ++++++++++++++++++ .../tracing/new-spans/migration-guide.mdx | 86 +++++++ .../dart.flutter.mdx | 10 + .../span-streaming-enable-diff/dart.mdx | 7 + .../span-streaming-enable/dart.flutter.mdx | 16 ++ .../span-streaming-enable/dart.mdx | 12 + 6 files changed, 361 insertions(+) create mode 100644 docs/platforms/dart/common/tracing/new-spans/index.mdx create mode 100644 docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx create mode 100644 platform-includes/performance/span-streaming-enable-diff/dart.flutter.mdx create mode 100644 platform-includes/performance/span-streaming-enable-diff/dart.mdx create mode 100644 platform-includes/performance/span-streaming-enable/dart.flutter.mdx create mode 100644 platform-includes/performance/span-streaming-enable/dart.mdx diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx new file mode 100644 index 0000000000000..1898e90a60ae2 --- /dev/null +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -0,0 +1,230 @@ +--- +title: New Spans +description: "Learn how to use stream mode to send spans to Sentry as they finish, removing the 1,000-span limit and making trace data visible sooner." +sidebar_order: 10 +new: true +--- + +By default, the Sentry SDK collects all spans in memory and sends them to Sentry as a single transaction once the root span ends. This is called transaction mode. +Stream mode changes this by sending spans to Sentry in batches as they finish, instead of waiting for the whole transaction to complete. + + + +- **No 1,000-span limit.** In transaction mode, transactions are capped at 1,000 spans. Stream mode has no upper limit since spans are sent in batches as they finish. +- **Lower memory usage.** Spans are flushed as they complete instead of being held in memory until the root span ends. This is especially useful for long-lived screens and background isolates. +- **Faster visibility.** Span data arrives in Sentry as your app runs, instead of only after the entire operation completes. +- **Fewer spans lost to crashes.** If your app terminates unexpectedly, spans that were already flushed are still delivered. In transaction mode, a crash before the transaction ends means all of its span data is lost. + + + +You can find the following span types mentioned throughout this page: + +- **Root span**: The topmost span in a trace. It has no parent span, and sampling decisions are made here. +- **Child span**: Any span nested under a parent span within the same trace. + +This graph shows how these span types relate to each other within a trace: + +``` +Trace +│ +└── Root span + ├── Child span + │ └── Child span + └── Child span +``` + + + +Stream mode replaces the transaction-based APIs with new span APIs, so migrating to stream mode and adopting the new span APIs are the same step. If you have existing custom instrumentation, see the Migration Guide for a full list of changes. + + + +## Prerequisites + +You need: + +- Tracing configured in + your app +- Sentry SDK `>=9.19.0` + +## Enable Stream Mode + +Opt in by setting `traceLifecycle` to `SentryTraceLifecycle.stream` when initializing the SDK. This is the only required config change: + + + +To revert to transaction mode, remove the option or set `traceLifecycle` to `SentryTraceLifecycle.static` (the default). + +You can only use one tracing system at a time: + +- In `stream` mode, the transaction APIs (`Sentry.startTransaction`, `ISentrySpan.startChild`) do nothing and log a warning. +- In `static` mode, the new span APIs (`Sentry.startSpan`) do nothing. +- Auto-instrumentations switch to the correct API automatically based on this setting. + +## Manual Instrumentation (Optional) + +The SDK instruments common operations for you, but you can wrap your own code in spans to measure anything that matters to your app. + +### Start a Span + +`Sentry.startSpan` runs a callback and ends the span when the returned future completes. Spans created inside an active span are automatically associated with the parent through zones, so there's no separate "child span" call to make — just nest: + +```dart +await Sentry.startSpan('checkout', (span) async { + await Sentry.startSpan('load cart', (_) => loadCart()); + + await Sentry.startSpan('submit payment', (_) => submitPayment()); +}); +``` + +Error handling is automatic: if the callback throws (or its future errors), the span status is set to `error` before the span ends and the error is rethrown. Otherwise the status defaults to `ok`. + +For synchronous work, use `Sentry.startSpanSync`. Both variants can be freely nested, and parent-child relationships resolve correctly across sync and async boundaries: + +```dart +final config = Sentry.startSpanSync('parse-config', (_) { + return Config.parse(raw); +}); +``` + +If a span isn't sampled, the callback still runs and receives a no-op span, so all span operations remain safe to call. + +#### Spans That Outlive a Callback + +Use `Sentry.startInactiveSpan` when the work can't be wrapped in a single callback — widget lifecycles, stream subscriptions, or platform channel round-trips. You must call `end()` manually, and other spans do **not** automatically become its children: + +```dart +final paymentSpan = Sentry.startInactiveSpan( + 'payment', + attributes: {'payment.provider': SentryAttribute.string('stripe')}, +); + +// ...later, from a different entry point +void onPaymentComplete() { + paymentSpan.end(); +} +``` + +#### Control Parenting + +By default, a span inherits the currently active span as its parent. To change this, pass `parentSpan`: + +- `parentSpan: null` forces a root span with no parent. +- `parentSpan: someSpan` parents the new span under a specific `SentrySpanV2`. + +This applies to `startSpan`, `startSpanSync`, and `startInactiveSpan`. + +#### Set Span Timing Retroactively + +When the real start or end of the work happened before you could create or end the span — for example, a duration measured by a platform channel — pass `startTimestamp` or an explicit end time: + +```dart +// startTimestamp is available on the callback variants +Sentry.startSpanSync('replay-import', (_) => importRows(), + startTimestamp: measuredStart); + +final paymentSpan = Sentry.startInactiveSpan('payment'); +// ...native reports the work ended at `nativeEnd` +paymentSpan.end(endTimestamp: nativeEnd); +``` + +### Add Span Attributes + +Streamed spans use typed attributes instead of untyped data and tags. Set them with `setAttribute` or `setAttributes`, and remove them with `removeAttribute`: + +```dart +await Sentry.startSpan('process-order', (span) async { + span.setAttribute('order.id', SentryAttribute.string('abc-123')); + + span.setAttributes({ + 'order.item_count': SentryAttribute.int(5), + 'order.priority': SentryAttribute.bool(true), + 'order.total': SentryAttribute.double(42.50), + }); + + await processOrder(); +}); +``` + +Each attribute value is created with a typed `SentryAttribute` factory: + +| Factory | Dart Type | +| --------------------------- | --------- | +| `SentryAttribute.string(v)` | `String` | +| `SentryAttribute.int(v)` | `int` | +| `SentryAttribute.bool(v)` | `bool` | +| `SentryAttribute.double(v)` | `double` | + + + +Sentry automatically sets several standard attributes on spans. To avoid accidentally overwriting these, refer to our Sentry Attribute Conventions. + + + +### Set Span Status + +The status is set automatically — `error` if the callback throws, `ok` otherwise — so you only need to set it manually to override the default: + +```dart +await Sentry.startSpan('sync', (span) async { + if (!await isReachable()) { + span.status = SentrySpanStatusV2.error; + return; + } + await sync(); +}); +``` + +Status can only be `SentrySpanStatusV2.ok` or `SentrySpanStatusV2.error`. + +## Extended Configuration (Optional) + +You can shape what ends up in Sentry by filtering span data or dropping spans entirely. + +### Filter Spans + +To modify or redact span data before it's sent, use `beforeSendSpan`. It receives each `SentrySpanV2` before it's sent. Unlike other `beforeSend` callbacks, it **cannot drop spans** — it's mutation-only. Use [`ignoreSpans`](#drop-spans) to drop spans instead. + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + +### Drop Spans + +To prevent specific spans from being sent, use `ignoreSpans`. Rules match against the span name (attribute matching isn't supported yet in the Dart SDK): + +```dart +options.ignoreSpans = [ + IgnoreSpanRule.nameEquals('health-check'), + IgnoreSpanRule.nameStartsWith('internal.'), + IgnoreSpanRule.nameContains('metrics'), + IgnoreSpanRule.nameEndsWith('.bg'), +]; +``` + +| Factory | Matches | +| ---------------------------------------- | --------------------------------- | +| `IgnoreSpanRule.nameEquals(String)` | Exact span name | +| `IgnoreSpanRule.nameStartsWith(Pattern)` | Name prefix (String or RegExp) | +| `IgnoreSpanRule.nameContains(Pattern)` | Name substring (String or RegExp) | +| `IgnoreSpanRule.nameEndsWith(String)` | Name suffix | + +When an ignored span has children, the children are re-parented to the nearest recording ancestor rather than dropped. + +## Sampling (Optional) + +If you use `tracesSampleRate` or a custom `tracesSampler`, no changes are needed — both work the same way in stream mode. Only **root spans** are sampled; child spans inherit the root's decision. When a root span isn't sampled, its callback still executes with a no-op span. + +## Flutter Auto-Instrumentation + +No code changes are needed. Frames tracking, app start, TTID/TTFD, navigation, user interaction, HTTP, database, and GraphQL instrumentations all switch to the streaming API automatically when `traceLifecycle` is `stream`. + +## Verify Your Setup + +To make sure you've enabled stream mode successfully: + +- **Check the Sentry dashboard**: Spans should appear in the Traces view shortly after each span completes, without waiting for a whole transaction to finish. Spans are buffered briefly and flushed in batches, so expect a short delay before they appear. +- **Check the envelopes**: With `options.debug = true` or network inspection, span envelopes are sent with the content type `application/vnd.sentry.items.span.v2+json` instead of transaction envelopes. +- **Check your logs**: A log line like `startTransaction is not supported when traceLifecycle is 'stream'` means the legacy transaction API is still being called somewhere in your code. See the Migration Guide to update it. diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx new file mode 100644 index 0000000000000..a84bd93bc4de3 --- /dev/null +++ b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx @@ -0,0 +1,86 @@ +--- +title: Migrate to Stream Mode +sidebar_order: 10 +description: "Learn how to migrate your custom instrumentation from transaction mode to stream mode." +--- + +Stream mode replaces the transaction-based APIs with new span APIs. If you use custom instrumentation (creating transactions manually, setting span data, or filtering spans) you'll need to update that code before switching to stream mode. This guide walks through the changes. + +For an introduction to stream mode itself, see New Spans. + +## Enable Stream Mode + +Set `traceLifecycle` to `SentryTraceLifecycle.stream` when initializing the SDK: + + + +In `stream` mode, the transaction APIs (`Sentry.startTransaction`, `ISentrySpan.startChild`) become no-ops and log a warning, so you need to migrate any manual usage. + +## Span Creation + +Replace `Sentry.startTransaction` and `span.startChild` with `Sentry.startSpan`. `startSpan` runs a callback and ends the span when the returned future completes. Nested calls auto-parent through zones, so there's no `startChild` equivalent — just nest: + +```dart diff +- final transaction = Sentry.startTransaction('checkout', 'task'); +- try { +- final child = transaction.startChild('db.query', description: 'load cart'); +- final cart = await loadCart(); +- await child.finish(); +- transaction.setData('cart.item_count', cart.items.length); +- } finally { +- await transaction.finish(); +- } ++ await Sentry.startSpan('checkout', (span) async { ++ final cart = await Sentry.startSpan('load cart', (_) => loadCart()); ++ span.setAttribute('cart.item_count', SentryAttribute.int(cart.items.length)); ++ }); +``` + +For synchronous work, use `Sentry.startSpanSync` instead. When the work can't be wrapped in a single callback (widget lifecycles, stream subscriptions, platform channels), use `Sentry.startInactiveSpan` and call `end()` manually. See Start a Span for details. + +## Span Attributes + +Streamed spans have no untyped data or tags — everything is a typed attribute. Replace `setData` and `setTag` with `setAttribute` or `setAttributes`: + +```dart diff +- span.setData('retry_count', 3); +- span.setTag('payment.provider', 'stripe'); ++ span.setAttribute('retry_count', SentryAttribute.int(3)); ++ span.setAttribute('payment.provider', SentryAttribute.string('stripe')); +``` + +Attribute values must be created with a typed `SentryAttribute` factory (`string`, `int`, `bool`, or `double`). See Add Span Attributes for the full list. + +## Span Status + +In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2`, which can only be `ok` or `error`: + +```dart diff +- transaction.status = const SpanStatus.internalError(); ++ span.status = SentrySpanStatusV2.error; +``` + +Manual assignment is only needed to override the automatic default. + +## Filtering and Dropping Spans + +`beforeSendTransaction` has **no effect** in stream mode — transactions are never created, so the callback is never invoked. Migrate its logic to `beforeSendSpan` (to modify spans) and `ignoreSpans` (to drop them): + +```dart diff +- options.beforeSendTransaction = (transaction) { +- // scrub sensitive data, drop transactions by name, etc. +- return transaction; +- }; ++ options.beforeSendSpan = (span) { ++ span.removeAttribute('http.request.body'); ++ }; ++ options.ignoreSpans = [ ++ IgnoreSpanRule.nameEquals('health-check'), ++ ]; +``` + +Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. Both only have access to the span name and attributes set at creation time, not attributes added later in the span's lifetime. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. + +## Sampling + +`tracesSampleRate` and `tracesSampler` work unchanged. Only **root spans** are sampled; child spans inherit the root's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. diff --git a/platform-includes/performance/span-streaming-enable-diff/dart.flutter.mdx b/platform-includes/performance/span-streaming-enable-diff/dart.flutter.mdx new file mode 100644 index 0000000000000..526202196eb00 --- /dev/null +++ b/platform-includes/performance/span-streaming-enable-diff/dart.flutter.mdx @@ -0,0 +1,10 @@ +```dart diff + await SentryFlutter.init( + (options) { + options.dsn = '___PUBLIC_DSN___'; + options.tracesSampleRate = 1.0; ++ options.traceLifecycle = SentryTraceLifecycle.stream; + }, + appRunner: () => runApp(const MyApp()), + ); +``` diff --git a/platform-includes/performance/span-streaming-enable-diff/dart.mdx b/platform-includes/performance/span-streaming-enable-diff/dart.mdx new file mode 100644 index 0000000000000..8c929de6d2ac6 --- /dev/null +++ b/platform-includes/performance/span-streaming-enable-diff/dart.mdx @@ -0,0 +1,7 @@ +```dart diff + await Sentry.init((options) { + options.dsn = '___PUBLIC_DSN___'; + options.tracesSampleRate = 1.0; ++ options.traceLifecycle = SentryTraceLifecycle.stream; + }); +``` diff --git a/platform-includes/performance/span-streaming-enable/dart.flutter.mdx b/platform-includes/performance/span-streaming-enable/dart.flutter.mdx new file mode 100644 index 0000000000000..578a2a58c5237 --- /dev/null +++ b/platform-includes/performance/span-streaming-enable/dart.flutter.mdx @@ -0,0 +1,16 @@ +```dart +import 'package:flutter/widgets.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +Future main() async { + await SentryFlutter.init( + (options) { + options.dsn = '___PUBLIC_DSN___'; + options.tracesSampleRate = 1.0; + // Enables stream mode + options.traceLifecycle = SentryTraceLifecycle.stream; + }, + appRunner: () => runApp(const MyApp()), + ); +} +``` diff --git a/platform-includes/performance/span-streaming-enable/dart.mdx b/platform-includes/performance/span-streaming-enable/dart.mdx new file mode 100644 index 0000000000000..cfd22a73f4996 --- /dev/null +++ b/platform-includes/performance/span-streaming-enable/dart.mdx @@ -0,0 +1,12 @@ +```dart +import 'package:sentry/sentry.dart'; + +Future main() async { + await Sentry.init((options) { + options.dsn = '___PUBLIC_DSN___'; + options.tracesSampleRate = 1.0; + // Enables stream mode + options.traceLifecycle = SentryTraceLifecycle.stream; + }); +} +``` From 8d7ee35fde0e190a97d81159d5302f26a0a37fbf Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Wed, 1 Jul 2026 00:00:02 +0200 Subject: [PATCH 02/14] docs(dart): Correct stream mode sampling and beforeSendSpan details Fix two factual errors in the New Spans pages verified against the SDK source: a custom tracesSampler receives a different sampling context in stream mode (read name and attributes from spanContext, not the transaction context), and beforeSendSpan runs when each span ends and sees all attributes rather than only creation-time ones. Also add the service span type to the span taxonomy. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../dart/common/tracing/new-spans/index.mdx | 17 ++++++++++++++++- .../tracing/new-spans/migration-guide.mdx | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx index 1898e90a60ae2..15c796bb2b6ce 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -20,6 +20,7 @@ Stream mode changes this by sending spans to Sentry in batches as they finish, i You can find the following span types mentioned throughout this page: - **Root span**: The topmost span in a trace. It has no parent span, and sampling decisions are made here. +- **Service span**: A top-level span with no parent, created with `parentSpan: null`. It's the stream mode equivalent of a transaction. The first service span in a trace is also its root span. - **Child span**: Any span nested under a parent span within the same trace. This graph shows how these span types relate to each other within a trace: @@ -215,7 +216,21 @@ When an ignored span has children, the children are re-parented to the nearest r ## Sampling (Optional) -If you use `tracesSampleRate` or a custom `tracesSampler`, no changes are needed — both work the same way in stream mode. Only **root spans** are sampled; child spans inherit the root's decision. When a root span isn't sampled, its callback still executes with a no-op span. +`tracesSampleRate` works the same way in stream mode, so no changes are needed if that's all you use. + +A custom `tracesSampler`, however, receives a different sampling context in stream mode. Instead of a transaction context, read the span's `name` and `attributes` from `samplingContext.spanContext`: + +```dart +options.tracesSampler = (samplingContext) { + final spanContext = samplingContext.spanContext; + if (spanContext.name == 'health-check') { + return 0.0; + } + return 0.2; +}; +``` + +Only **root spans** are sampled; child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. ## Flutter Auto-Instrumentation diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx index a84bd93bc4de3..1d67ebd1d3836 100644 --- a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx @@ -79,8 +79,21 @@ Manual assignment is only needed to override the automatic default. + ]; ``` -Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. Both only have access to the span name and attributes set at creation time, not attributes added later in the span's lifetime. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. +Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. `beforeSendSpan` runs when each span ends, so it sees the full set of attributes, including any added during the span's lifetime. `ignoreSpans`, by contrast, is evaluated when a span is created and matches on the span name only. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. ## Sampling -`tracesSampleRate` and `tracesSampler` work unchanged. Only **root spans** are sampled; child spans inherit the root's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. +`tracesSampleRate` works unchanged. A custom `tracesSampler` still works, but the sampling context changes: read the span's `name` and `attributes` from `samplingContext.spanContext` instead of the transaction context. + +```dart diff +- options.tracesSampler = (samplingContext) { +- final name = samplingContext.transactionContext.name; +- // ... +- }; ++ options.tracesSampler = (samplingContext) { ++ final name = samplingContext.spanContext.name; ++ // ... ++ }; +``` + +Only **root spans** are sampled; child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. See Sampling for details. From 4553eef241df81c043e3c9e4c803376cb3f87ca7 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 6 Jul 2026 11:57:30 +0200 Subject: [PATCH 03/14] docs(dart): Bump span streaming min SDK version to 9.23.0 Co-Authored-By: Claude --- docs/platforms/dart/common/tracing/new-spans/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx index 15c796bb2b6ce..ad84af2818b39 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -46,7 +46,7 @@ You need: - Tracing configured in your app -- Sentry SDK `>=9.19.0` +- Sentry SDK `>=9.23.0` ## Enable Stream Mode From 0176a7962911c82bc13ba637b4e84a3d93763fa6 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 6 Jul 2026 14:10:46 +0200 Subject: [PATCH 04/14] docs(dart): Document array attributes and startSpanSync signature Add the array SentryAttribute factories (stringArray/intArray/boolArray/ doubleArray) to the attributes table and clarify that startSpanSync is the synchronous variant of startSpan (T vs Future callback). Co-Authored-By: Claude --- .../dart/common/tracing/new-spans/index.mdx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx index ad84af2818b39..d517b15d88d05 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -80,7 +80,7 @@ await Sentry.startSpan('checkout', (span) async { Error handling is automatic: if the callback throws (or its future errors), the span status is set to `error` before the span ends and the error is rethrown. Otherwise the status defaults to `ok`. -For synchronous work, use `Sentry.startSpanSync`. Both variants can be freely nested, and parent-child relationships resolve correctly across sync and async boundaries: +`Sentry.startSpan` takes an asynchronous callback (returning `Future`). For synchronous work, use `Sentry.startSpanSync`, which takes a synchronous callback (returning `T`). Both variants can be freely nested, and parent-child relationships resolve correctly across sync and async boundaries: ```dart final config = Sentry.startSpanSync('parse-config', (_) { @@ -149,12 +149,16 @@ await Sentry.startSpan('process-order', (span) async { Each attribute value is created with a typed `SentryAttribute` factory: -| Factory | Dart Type | -| --------------------------- | --------- | -| `SentryAttribute.string(v)` | `String` | -| `SentryAttribute.int(v)` | `int` | -| `SentryAttribute.bool(v)` | `bool` | -| `SentryAttribute.double(v)` | `double` | +| Factory | Dart Type | +| -------------------------------- | -------------- | +| `SentryAttribute.string(v)` | `String` | +| `SentryAttribute.int(v)` | `int` | +| `SentryAttribute.bool(v)` | `bool` | +| `SentryAttribute.double(v)` | `double` | +| `SentryAttribute.stringArray(v)` | `List` | +| `SentryAttribute.intArray(v)` | `List` | +| `SentryAttribute.boolArray(v)` | `List` | +| `SentryAttribute.doubleArray(v)` | `List` | From 4f9a21b1e156c71debc4d861a26abc9e4657d330 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 6 Jul 2026 14:20:30 +0200 Subject: [PATCH 05/14] docs(dart): Correct SentrySpanStatusV2 possible values The enum has four values (ok, error, cancelled, deadlineExceeded), not just ok/error. Fix the New Spans and migration guide wording. Co-Authored-By: Claude --- docs/platforms/dart/common/tracing/new-spans/index.mdx | 2 +- .../platforms/dart/common/tracing/new-spans/migration-guide.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx index d517b15d88d05..f9cc7ab306c23 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -180,7 +180,7 @@ await Sentry.startSpan('sync', (span) async { }); ``` -Status can only be `SentrySpanStatusV2.ok` or `SentrySpanStatusV2.error`. +You can set any `SentrySpanStatusV2` value: `ok`, `error`, `cancelled`, or `deadlineExceeded`. When you don't set it, the status defaults to `ok`, or `error` if the callback throws. ## Extended Configuration (Optional) diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx index 1d67ebd1d3836..47b761a99c748 100644 --- a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx @@ -53,7 +53,7 @@ Attribute values must be created with a typed `SentryAttribute` factory (`string ## Span Status -In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2`, which can only be `ok` or `error`: +In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2` (`ok`, `error`, `cancelled`, or `deadlineExceeded`): ```dart diff - transaction.status = const SpanStatus.internalError(); From ec3c3a524d9d13bdb1fc7abc026373c99c53fd4e Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 6 Jul 2026 14:22:26 +0200 Subject: [PATCH 06/14] docs(dart): Revert span status to ok/error only Per SDK maintainer: only ok and error are valid stream-mode span statuses. Co-Authored-By: Claude --- docs/platforms/dart/common/tracing/new-spans/index.mdx | 2 +- .../platforms/dart/common/tracing/new-spans/migration-guide.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/new-spans/index.mdx index f9cc7ab306c23..d517b15d88d05 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/index.mdx @@ -180,7 +180,7 @@ await Sentry.startSpan('sync', (span) async { }); ``` -You can set any `SentrySpanStatusV2` value: `ok`, `error`, `cancelled`, or `deadlineExceeded`. When you don't set it, the status defaults to `ok`, or `error` if the callback throws. +Status can only be `SentrySpanStatusV2.ok` or `SentrySpanStatusV2.error`. ## Extended Configuration (Optional) diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx index 47b761a99c748..1d67ebd1d3836 100644 --- a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx @@ -53,7 +53,7 @@ Attribute values must be created with a typed `SentryAttribute` factory (`string ## Span Status -In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2` (`ok`, `error`, `cancelled`, or `deadlineExceeded`): +In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2`, which can only be `ok` or `error`: ```dart diff - transaction.status = const SpanStatus.internalError(); From 6283b01a018939c82f022caf0c37318597854a07 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 6 Jul 2026 15:43:28 +0200 Subject: [PATCH 07/14] docs(dart): Note scope tags don't apply to spans in stream mode Mirror the Python migration guide: scope setTag isn't applied to streamed spans; use Sentry.setAttributes to set span-applying attributes. Co-Authored-By: Claude --- .../platforms/dart/common/tracing/new-spans/migration-guide.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx index 1d67ebd1d3836..42fffd47d80fa 100644 --- a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx @@ -51,6 +51,8 @@ Streamed spans have no untyped data or tags — everything is a typed attribute. Attribute values must be created with a typed `SentryAttribute` factory (`string`, `int`, `bool`, or `double`). See Add Span Attributes for the full list. +Tags set on the scope (`Sentry.configureScope((scope) => scope.setTag(...))`) aren't applied to spans in stream mode. Use `Sentry.setAttributes(...)` to set attributes that apply to your spans instead. + ## Span Status In stream mode, status is set automatically — `error` if the callback throws, `ok` otherwise. Explicit statuses from the old API migrate to the typed `SentrySpanStatusV2`, which can only be `ok` or `error`: From 4bddae25e6f3c27c9198fd608625ba3bedfe51c2 Mon Sep 17 00:00:00 2001 From: inventarSarah Date: Wed, 8 Jul 2026 15:13:17 +0200 Subject: [PATCH 08/14] rename new spans to streamed spans; update pages for consistency with Python guides --- .../{new-spans => streamed-spans}/index.mdx | 259 +++++++++++++++--- .../migration-guide.mdx | 94 +++++-- 2 files changed, 299 insertions(+), 54 deletions(-) rename docs/platforms/dart/common/tracing/{new-spans => streamed-spans}/index.mdx (59%) rename docs/platforms/dart/common/tracing/{new-spans => streamed-spans}/migration-guide.mdx (55%) diff --git a/docs/platforms/dart/common/tracing/new-spans/index.mdx b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx similarity index 59% rename from docs/platforms/dart/common/tracing/new-spans/index.mdx rename to docs/platforms/dart/common/tracing/streamed-spans/index.mdx index d517b15d88d05..4d4b5d938c189 100644 --- a/docs/platforms/dart/common/tracing/new-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -1,5 +1,5 @@ --- -title: New Spans +title: Streamed Spans description: "Learn how to use stream mode to send spans to Sentry as they finish, removing the 1,000-span limit and making trace data visible sooner." sidebar_order: 10 new: true @@ -28,15 +28,17 @@ This graph shows how these span types relate to each other within a trace: ``` Trace │ -└── Root span +└── Root span [service A] ├── Child span │ └── Child span - └── Child span + └── Service span [service B] + ├── Child span + └── Child span ``` -Stream mode replaces the transaction-based APIs with new span APIs, so migrating to stream mode and adopting the new span APIs are the same step. If you have existing custom instrumentation, see the Migration Guide for a full list of changes. +Stream mode replaces the transaction-based APIs with new span APIs, so migrating to stream mode and adopting the new span APIs are the same step. If you have existing custom instrumentation, see the Migration Guide for a full list of changes. @@ -50,17 +52,52 @@ You need: ## Enable Stream Mode + + + + Opt in by setting `traceLifecycle` to `SentryTraceLifecycle.stream` when initializing the SDK. This is the only required config change: + + + + + + + To revert to transaction mode, remove the option or set `traceLifecycle` to `SentryTraceLifecycle.static` (the default). You can only use one tracing system at a time: - In `stream` mode, the transaction APIs (`Sentry.startTransaction`, `ISentrySpan.startChild`) do nothing and log a warning. - In `static` mode, the new span APIs (`Sentry.startSpan`) do nothing. -- Auto-instrumentations switch to the correct API automatically based on this setting. + + + Auto-instrumentations switch to the correct API automatically based on this + setting. + + + Auto-instrumentations switch to the correct API automatically based on this + setting. This includes Flutter's frames tracking, app start, TTID/TTFD, + navigation, user interaction, HTTP, database, and GraphQL instrumentations. + + + + +When stream mode is enabled, the SDK maintains an internal buffer that groups spans by trace ID. + +Spans are flushed: + +- On a regular interval (every 5 seconds by default). +- When a trace's buffer reaches 1,000 spans. +- When the SDK shuts down. +- When the internal buffer size exceeds 1 MiB. + +Each flush sends only the spans accumulated since the last flush, grouped into envelopes by trace ID. + + ## Manual Instrumentation (Optional) @@ -68,7 +105,30 @@ The SDK instruments common operations for you, but you can wrap your own code in ### Start a Span -`Sentry.startSpan` runs a callback and ends the span when the returned future completes. Spans created inside an active span are automatically associated with the parent through zones, so there's no separate "child span" call to make — just nest: + + + + +`Sentry.startSpan` runs a callback and ends the span when the returned future completes. + + + + +```dart +await Sentry.startSpan('checkout', (span) async { + // Your code here +}); +``` + + + + + + +Child spans created inside an active span are automatically associated with the parent through zones: + + + ```dart await Sentry.startSpan('checkout', (span) async { @@ -78,21 +138,88 @@ await Sentry.startSpan('checkout', (span) async { }); ``` -Error handling is automatic: if the callback throws (or its future errors), the span status is set to `error` before the span ends and the error is rethrown. Otherwise the status defaults to `ok`. + + + + + +By default, a span inherits the currently active span as its parent. To change this, pass `parentSpan`: + +- `parentSpan: null` forces a service span with no parent. +- `parentSpan: someSpan` parents the new span under a specific span. + + + + +```dart + +// force a new service span +await Sentry.startSpan( + 'checkout-flow', + (span) async { + await runCheckout(); + }, + parentSpan: null, +); + +// start a child span with a specific parent +final parent = Sentry.startInactiveSpan( + 'background-sync', + parentSpan: null, +); + +try { + await someOtherAsyncBoundary(); + + await Sentry.startSpan( + 'fetch-page', + (child) async { + await api.fetchPage(); + }, + parentSpan: parent, + ); +} finally { + parent.end(); +} +``` + + + + + +#### Create Spans for Synchronous Work + + + + `Sentry.startSpan` takes an asynchronous callback (returning `Future`). For synchronous work, use `Sentry.startSpanSync`, which takes a synchronous callback (returning `T`). Both variants can be freely nested, and parent-child relationships resolve correctly across sync and async boundaries: + + + ```dart final config = Sentry.startSpanSync('parse-config', (_) { return Config.parse(raw); }); ``` + + + + If a span isn't sampled, the callback still runs and receives a no-op span, so all span operations remain safe to call. -#### Spans That Outlive a Callback +#### Create Spans That Outlive a Callback -Use `Sentry.startInactiveSpan` when the work can't be wrapped in a single callback — widget lifecycles, stream subscriptions, or platform channel round-trips. You must call `end()` manually, and other spans do **not** automatically become its children: + + + + +Use `Sentry.startInactiveSpan` when the work can't be wrapped in a single callback — widget lifecycles, stream subscriptions, or platform channel round-trips. You have to call `end()` manually, and other spans do **not** automatically become its children — to nest a span under it, pass it explicitly via `parentSpan` when starting the child. + + + ```dart final paymentSpan = Sentry.startInactiveSpan( @@ -106,18 +233,20 @@ void onPaymentComplete() { } ``` -#### Control Parenting + + + -By default, a span inherits the currently active span as its parent. To change this, pass `parentSpan`: +#### Retroactively Set Span Timing -- `parentSpan: null` forces a root span with no parent. -- `parentSpan: someSpan` parents the new span under a specific `SentrySpanV2`. + + + -This applies to `startSpan`, `startSpanSync`, and `startInactiveSpan`. +When the real start or end of the work happened before you could create or end the span (for example, a duration measured by a platform channel) pass `startTimestamp` or an explicit `end` time: -#### Set Span Timing Retroactively - -When the real start or end of the work happened before you could create or end the span — for example, a duration measured by a platform channel — pass `startTimestamp` or an explicit end time: + + ```dart // startTimestamp is available on the callback variants @@ -129,9 +258,26 @@ final paymentSpan = Sentry.startInactiveSpan('payment'); paymentSpan.end(endTimestamp: nativeEnd); ``` + + + + ### Add Span Attributes -Streamed spans use typed attributes instead of untyped data and tags. Set them with `setAttribute` or `setAttributes`, and remove them with `removeAttribute`: + + + + +Attach structured metadata to spans using `setAttribute` or `setAttributes`, and remove them with `removeAttribute`. + + + +Sentry automatically sets several standard attributes on spans. To avoid accidentally overwriting these, refer to our Sentry Attribute Conventions. + + + + + ```dart await Sentry.startSpan('process-order', (span) async { @@ -147,6 +293,12 @@ await Sentry.startSpan('process-order', (span) async { }); ``` + + + + + + Each attribute value is created with a typed `SentryAttribute` factory: | Factory | Dart Type | @@ -160,15 +312,13 @@ Each attribute value is created with a typed `SentryAttribute` factory: | `SentryAttribute.boolArray(v)` | `List` | | `SentryAttribute.doubleArray(v)` | `List` | - - -Sentry automatically sets several standard attributes on spans. To avoid accidentally overwriting these, refer to our Sentry Attribute Conventions. - - + ### Set Span Status -The status is set automatically — `error` if the callback throws, `ok` otherwise — so you only need to set it manually to override the default: +Error handling is automatic: if the callback throws (or its future errors), the span status is set to `error` before the span ends and the error is rethrown. Otherwise the status defaults to `ok`. + +Status can only be `SentrySpanStatusV2.ok` or `SentrySpanStatusV2.error`: ```dart await Sentry.startSpan('sync', (span) async { @@ -180,15 +330,20 @@ await Sentry.startSpan('sync', (span) async { }); ``` -Status can only be `SentrySpanStatusV2.ok` or `SentrySpanStatusV2.error`. - ## Extended Configuration (Optional) You can shape what ends up in Sentry by filtering span data or dropping spans entirely. ### Filter Spans -To modify or redact span data before it's sent, use `beforeSendSpan`. It receives each `SentrySpanV2` before it's sent. Unlike other `beforeSend` callbacks, it **cannot drop spans** — it's mutation-only. Use [`ignoreSpans`](#drop-spans) to drop spans instead. + + + + +To modify or redact span data before it's sent, use `beforeSendSpan`: + + + ```dart options.beforeSendSpan = (span) { @@ -196,9 +351,26 @@ options.beforeSendSpan = (span) { }; ``` + + + + + + +`beforeSendSpan` runs after the span ends, so it has access to all attributes set during its lifetime. To drop spans instead of modifying them, use [`ignoreSpans`](#drop-spans). + + + ### Drop Spans -To prevent specific spans from being sent, use `ignoreSpans`. Rules match against the span name (attribute matching isn't supported yet in the Dart SDK): + + + + +To prevent specific spans from being sent, use `ignoreSpans`. Rules are evaluated at span start and match against the span name. Attribute-based matching is not yet supported. + + + ```dart options.ignoreSpans = [ @@ -209,6 +381,12 @@ options.ignoreSpans = [ ]; ``` + + + + + + | Factory | Matches | | ---------------------------------------- | --------------------------------- | | `IgnoreSpanRule.nameEquals(String)` | Exact span name | @@ -216,13 +394,22 @@ options.ignoreSpans = [ | `IgnoreSpanRule.nameContains(Pattern)` | Name substring (String or RegExp) | | `IgnoreSpanRule.nameEndsWith(String)` | Name suffix | + + When an ignored span has children, the children are re-parented to the nearest recording ancestor rather than dropped. ## Sampling (Optional) -`tracesSampleRate` works the same way in stream mode, so no changes are needed if that's all you use. +If you use `tracesSampleRate`, no changes are needed — it works the same way in stream mode. + + + + -A custom `tracesSampler`, however, receives a different sampling context in stream mode. Instead of a transaction context, read the span's `name` and `attributes` from `samplingContext.spanContext`: +If you use a custom `tracesSampler`, the shape of the sampling context is different in stream mode. Instead of a transaction context, read the span's `name` and `attributes` from `samplingContext.spanContext`: + + + ```dart options.tracesSampler = (samplingContext) { @@ -234,16 +421,16 @@ options.tracesSampler = (samplingContext) { }; ``` -Only **root spans** are sampled; child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. - -## Flutter Auto-Instrumentation + + + -No code changes are needed. Frames tracking, app start, TTID/TTFD, navigation, user interaction, HTTP, database, and GraphQL instrumentations all switch to the streaming API automatically when `traceLifecycle` is `stream`. +Only **root spans** are sampled and child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. ## Verify Your Setup To make sure you've enabled stream mode successfully: - **Check the Sentry dashboard**: Spans should appear in the Traces view shortly after each span completes, without waiting for a whole transaction to finish. Spans are buffered briefly and flushed in batches, so expect a short delay before they appear. -- **Check the envelopes**: With `options.debug = true` or network inspection, span envelopes are sent with the content type `application/vnd.sentry.items.span.v2+json` instead of transaction envelopes. -- **Check your logs**: A log line like `startTransaction is not supported when traceLifecycle is 'stream'` means the legacy transaction API is still being called somewhere in your code. See the Migration Guide to update it. +- **Check the envelopes**: With `options.debug = true` or network inspection, check if the span envelopes are sent with the content type `application/vnd.sentry.items.span.v2+json` instead of transaction envelopes. +- **Check your logs**: If the SDK logs warnings about unsupported span operations, you may still be using the legacy Span API somewhere in your code. See the Migration Guide to update it. diff --git a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx similarity index 55% rename from docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx rename to docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx index 42fffd47d80fa..e2dbe3e0d0cae 100644 --- a/docs/platforms/dart/common/tracing/new-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx @@ -6,7 +6,7 @@ description: "Learn how to migrate your custom instrumentation from transaction Stream mode replaces the transaction-based APIs with new span APIs. If you use custom instrumentation (creating transactions manually, setting span data, or filtering spans) you'll need to update that code before switching to stream mode. This guide walks through the changes. -For an introduction to stream mode itself, see New Spans. +For an introduction to stream mode itself, see Streamed Spans. ## Enable Stream Mode @@ -14,44 +14,102 @@ Set `traceLifecycle` to `SentryTraceLifecycle.stream` when initializing the SDK: -In `stream` mode, the transaction APIs (`Sentry.startTransaction`, `ISentrySpan.startChild`) become no-ops and log a warning, so you need to migrate any manual usage. - ## Span Creation -Replace `Sentry.startTransaction` and `span.startChild` with `Sentry.startSpan`. `startSpan` runs a callback and ends the span when the returned future completes. Nested calls auto-parent through zones, so there's no `startChild` equivalent — just nest: +Replace `Sentry.startTransaction` and `span.startChild` with `Sentry.startSpan`. `startSpan` runs a callback and ends the span when the returned future completes. Whether the resulting span is a service span, a child span, or a sibling depends on the `parentSpan` argument and what's currently active. ```dart diff +// Starting what used to be a transaction: use parentSpan: null with startSpan to force a service span - final transaction = Sentry.startTransaction('checkout', 'task'); - try { -- final child = transaction.startChild('db.query', description: 'load cart'); -- final cart = await loadCart(); -- await child.finish(); -- transaction.setData('cart.item_count', cart.items.length); +- await runCheckout(); - } finally { - await transaction.finish(); - } + await Sentry.startSpan('checkout', (span) async { -+ final cart = await Sentry.startSpan('load cart', (_) => loadCart()); -+ span.setAttribute('cart.item_count', SentryAttribute.int(cart.items.length)); ++ span.setAttribute('sentry.op', 'task'); ++ await runCheckout(); ++ }, ++ parentSpan: null, ++); + +// Starting a child span: just start a span while the parent is active +- final transaction = Sentry.startTransaction('checkout', 'task'); +- try { +- final chargeSpan = transaction.startChild('charge-card'); +- try { +- await paymentService.charge(); +- } finally { +- await chargeSpan.finish(); +- } +- } finally { +- await transaction.finish(); +- } ++ await Sentry.startSpan('checkout', (checkoutSpan) async { ++ checkoutSpan.setAttribute('sentry.op', 'task'); ++ await Sentry.startSpan('charge-card', (chargeSpan) async { ++ await paymentService.charge(); ++ }); + }); + +// Starting a child span: if the span's parent should be a span that's currently not active, you can provide it explicitly +- final parent = Sentry.startTransaction('background-sync', 'task'); +- try { +- await someOtherAsyncBoundary(); +- final child = parent.startChild('fetch-page'); +- try { +- await api.fetchPage(); +- } finally { +- await child.finish(); +- } +- } finally { +- await parent.finish(); +- } ++ final parent = Sentry.startInactiveSpan( ++ 'background-sync', ++ parentSpan: null, ++ ); ++ ++ try { ++ await someOtherAsyncBoundary(); ++ await Sentry.startSpan( ++ 'fetch-page', ++ (child) async { ++ await api.fetchPage(); ++ }, ++ parentSpan: parent, ++ ); ++ } finally { ++ parent.end(); ++ } ``` -For synchronous work, use `Sentry.startSpanSync` instead. When the work can't be wrapped in a single callback (widget lifecycles, stream subscriptions, platform channels), use `Sentry.startInactiveSpan` and call `end()` manually. See Start a Span for details. + + +`op` is not a dedicated argument of `startSpan` — set it as the `sentry.op` attribute instead. + + + +For synchronous work, use `Sentry.startSpanSync` instead. When the work can't be wrapped in a single callback (widget lifecycles, stream subscriptions, platform channels), use `Sentry.startInactiveSpan` and call `end()` manually. See Start a Span for details. ## Span Attributes -Streamed spans have no untyped data or tags — everything is a typed attribute. Replace `setData` and `setTag` with `setAttribute` or `setAttributes`: +In stream mode, spans have no contexts, data, or tags — everything is a typed attribute. Replace `setData` and `setTag` with `setAttribute` or `setAttributes`: ```dart diff - span.setData('retry_count', 3); - span.setTag('payment.provider', 'stripe'); + span.setAttribute('retry_count', SentryAttribute.int(3)); -+ span.setAttribute('payment.provider', SentryAttribute.string('stripe')); ++ span.setAttributes({ ++ 'payment.provider': SentryAttribute.string('stripe'), ++ 'cache.hit': SentryAttribute.bool(true), ++ 'response_time_ms': SentryAttribute.double(12.5), ++}); ``` -Attribute values must be created with a typed `SentryAttribute` factory (`string`, `int`, `bool`, or `double`). See Add Span Attributes for the full list. +Attribute values must be created with a typed `SentryAttribute` factory (`string`, `int`, `bool`, or `double`). See Add Span Attributes for the full list. -Tags set on the scope (`Sentry.configureScope((scope) => scope.setTag(...))`) aren't applied to spans in stream mode. Use `Sentry.setAttributes(...)` to set attributes that apply to your spans instead. +Tags set on the scope with (`Sentry.configureScope((scope) => scope.setTag(...))`) aren't applied to spans in stream mode. Use `Sentry.setAttributes(...)` to set attributes that apply to your spans instead. ## Span Status @@ -66,7 +124,7 @@ Manual assignment is only needed to override the automatic default. ## Filtering and Dropping Spans -`beforeSendTransaction` has **no effect** in stream mode — transactions are never created, so the callback is never invoked. Migrate its logic to `beforeSendSpan` (to modify spans) and `ignoreSpans` (to drop them): +`beforeSendTransaction` has **no effect** in stream mode — transactions are never created, so the callback is never invoked. Migrate its logic to `beforeSendSpan` to modify spans and `ignoreSpans` to drop them: ```dart diff - options.beforeSendTransaction = (transaction) { @@ -81,7 +139,7 @@ Manual assignment is only needed to override the automatic default. + ]; ``` -Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. `beforeSendSpan` runs when each span ends, so it sees the full set of attributes, including any added during the span's lifetime. `ignoreSpans`, by contrast, is evaluated when a span is created and matches on the span name only. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. +Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. `beforeSendSpan` runs when each span ends, so it sees the full set of attributes, including any added during the span's lifetime. `ignoreSpans`, by contrast, is evaluated when a span is created and matches on the span name only. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. ## Sampling @@ -98,4 +156,4 @@ Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignor + }; ``` -Only **root spans** are sampled; child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. See Sampling for details. +Only **root spans** are sampled; child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. From 53c8e48129844a5fa42de989bc888d38743c559e Mon Sep 17 00:00:00 2001 From: inventarSarah Date: Thu, 9 Jul 2026 11:56:21 +0200 Subject: [PATCH 09/14] update root span wording in sampling --- docs/platforms/dart/common/tracing/streamed-spans/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx index 4d4b5d938c189..84e8236a12a68 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -425,7 +425,7 @@ options.tracesSampler = (samplingContext) { -Only **root spans** are sampled and child spans inherit the root span's decision. When a root span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. +Only service spans are sampled and child spans inherit the service span's decision. When a service span isn't sampled, its callback still executes with a no-op span, so all span operations remain safe to call. ## Verify Your Setup From 522b994f3c40da562902234e145cfd020d7ef8ae Mon Sep 17 00:00:00 2001 From: inventarSarah Date: Thu, 9 Jul 2026 12:02:50 +0200 Subject: [PATCH 10/14] fix setAttribute usage --- .../dart/common/tracing/streamed-spans/migration-guide.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx index e2dbe3e0d0cae..90de84b1f7c02 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx @@ -27,7 +27,7 @@ Replace `Sentry.startTransaction` and `span.startChild` with `Sentry.startSpan`. - await transaction.finish(); - } + await Sentry.startSpan('checkout', (span) async { -+ span.setAttribute('sentry.op', 'task'); ++ span.setAttribute('sentry.op', SentryAttribute.string('task')); + await runCheckout(); + }, + parentSpan: null, @@ -46,7 +46,7 @@ Replace `Sentry.startTransaction` and `span.startChild` with `Sentry.startSpan`. - await transaction.finish(); - } + await Sentry.startSpan('checkout', (checkoutSpan) async { -+ checkoutSpan.setAttribute('sentry.op', 'task'); ++ checkoutSpan.setAttribute('sentry.op', SentryAttribute.string('task')); + await Sentry.startSpan('charge-card', (chargeSpan) async { + await paymentService.charge(); + }); From 2ae853e6c77a09a8fcbcab4bd5bcd898e9ff1e22 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Tue, 14 Jul 2026 15:56:11 +0200 Subject: [PATCH 11/14] docs(dart): Clarify service span parenting Distinguish local parents from remote parents across service boundaries. Clean up the scope-tag wording and remove the leading blank line from the parentSpan example. Co-Authored-By: Claude --- docs/platforms/dart/common/tracing/streamed-spans/index.mdx | 5 ++--- .../dart/common/tracing/streamed-spans/migration-guide.mdx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx index 84e8236a12a68..772bf1f729723 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -20,7 +20,7 @@ Stream mode changes this by sending spans to Sentry in batches as they finish, i You can find the following span types mentioned throughout this page: - **Root span**: The topmost span in a trace. It has no parent span, and sampling decisions are made here. -- **Service span**: A top-level span with no parent, created with `parentSpan: null`. It's the stream mode equivalent of a transaction. The first service span in a trace is also its root span. +- **Service span**: The top-level span within a service boundary. It has no local parent, but it can have a remote parent in another service. Pass `parentSpan: null` to create one. It's the stream mode equivalent of a transaction. The first service span in a trace is also its root span. - **Child span**: Any span nested under a parent span within the same trace. This graph shows how these span types relate to each other within a trace: @@ -145,14 +145,13 @@ await Sentry.startSpan('checkout', (span) async { By default, a span inherits the currently active span as its parent. To change this, pass `parentSpan`: -- `parentSpan: null` forces a service span with no parent. +- `parentSpan: null` forces a service span with no local parent. - `parentSpan: someSpan` parents the new span under a specific span. ```dart - // force a new service span await Sentry.startSpan( 'checkout-flow', diff --git a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx index 90de84b1f7c02..3233e63fc2811 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx @@ -109,7 +109,7 @@ In stream mode, spans have no contexts, data, or tags — everything is a typed Attribute values must be created with a typed `SentryAttribute` factory (`string`, `int`, `bool`, or `double`). See Add Span Attributes for the full list. -Tags set on the scope with (`Sentry.configureScope((scope) => scope.setTag(...))`) aren't applied to spans in stream mode. Use `Sentry.setAttributes(...)` to set attributes that apply to your spans instead. +Tags set on the scope using `Sentry.configureScope((scope) => scope.setTag(...))` aren't applied to spans in stream mode. Use `Sentry.setAttributes(...)` to set attributes that apply to your spans instead. ## Span Status From a98947b2c1ac118652d86be6d3380399c054949e Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 20 Jul 2026 10:40:40 +0200 Subject: [PATCH 12/14] docs(dart): Cover stream mode across tracing pages (#18611) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## DESCRIBE YOUR PR Documents **stream mode** across the Dart/Flutter tracing pages. Following the Python precedent, code snippets gain a `Stream Mode` tab next to `Transaction Mode (Default)` (nothing is removed), and prose is genericized to cover both modes. - Custom instrumentation (page + 5 code includes) → dual Transaction/Stream tabs, `startSpan`-only - Automatic instrumentation & performance metrics → mode-neutral wording; `setMeasurement` → span attributes - Tracing setup + Verify → New Spans pointer and mode-aware wording - Distributed-trace custom instrumentation → notes that trace continuation isn't supported in stream mode yet - Transaction-name and features → mode notes Stacked on #18554 — review/merge that first. Ref: https://github.com/getsentry/sentry-dart/issues/3886 ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. - [ ] Urgent deadline (GA date, etc.): - [ ] Other deadline: - [x] None: Not urgent, can wait up to 1 week+ ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it. Thanks in advance for your help! ## PRE-MERGE CHECKLIST *Make sure you've checked the following before merging your changes:* - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) --------- Co-authored-by: Claude Co-authored-by: inventarSarah --- .../transaction-name/index.mdx | 6 +++ docs/platforms/dart/common/features/index.mdx | 2 +- docs/platforms/dart/common/tracing/index.mdx | 22 +++++---- .../automatic-instrumentation.mdx | 24 ++++++---- .../custom-instrumentation.mdx | 6 +++ .../instrumentation/performance-metrics.mdx | 6 +-- .../common/tracing/streamed-spans/index.mdx | 1 - .../custom-instrumentation/index.mdx | 7 +++ .../tracing/trace-propagation/index.mdx | 7 +++ .../transaction-name/index.mdx | 6 +++ .../dart/guides/flutter/tracing/index.mdx | 22 +++++---- .../automatic-instrumentation.mdx | 18 +++++--- .../custom-instrumentation.mdx | 6 +++ .../instrumentation/performance-metrics.mdx | 6 +-- .../tracing/trace-propagation/index.mdx | 7 +++ .../performance/add-spans-example/dart.mdx | 31 ++++++++++--- .../performance/connect-errors-spans/dart.mdx | 36 +++++++++++++-- .../custom-performance-metrics/dart.mdx | 18 +++++++- .../enable-manual-instrumentation/dart.mdx | 21 +++++++-- .../performance/improving-data/dart.mdx | 45 +++++++++++++++++-- .../performance/retrieve-transaction/dart.mdx | 16 +++++-- 21 files changed, 254 insertions(+), 59 deletions(-) diff --git a/docs/platforms/dart/common/enriching-events/transaction-name/index.mdx b/docs/platforms/dart/common/enriching-events/transaction-name/index.mdx index 79edb847015bb..b985963eb6b26 100644 --- a/docs/platforms/dart/common/enriching-events/transaction-name/index.mdx +++ b/docs/platforms/dart/common/enriching-events/transaction-name/index.mdx @@ -3,6 +3,12 @@ title: Transaction Name description: "Learn how to set or override the transaction name to capture the user and gain critical pieces of information that construct a unique identity in Sentry." --- + + +This page only applies to transaction mode. In stream mode, there's no separate transaction name — set the span name when you create it with `Sentry.startSpan('name', ...)`. See Streamed Spans for details. + + + The current transaction name is used to group transactions in our [Sentry Dashboards](/product/dashboards/sentry-dashboards/) product, as well as annotate error events with their point of failure. diff --git a/docs/platforms/dart/common/features/index.mdx b/docs/platforms/dart/common/features/index.mdx index fdbcf230f401c..c102434ecd5e5 100644 --- a/docs/platforms/dart/common/features/index.mdx +++ b/docs/platforms/dart/common/features/index.mdx @@ -17,7 +17,7 @@ Sentry's Dart SDK enables automatic reporting of errors and exceptions, and iden your event by storing additional files, such as config or log files. - User Feedback provides the ability to collect user information when an event occurs. -- Tracing creates transactions for: +- Tracing captures spans for: - HTTP requests. - Dio HTTP library. - File I/O Integration. diff --git a/docs/platforms/dart/common/tracing/index.mdx b/docs/platforms/dart/common/tracing/index.mdx index 614d6f9d7c867..07ed5c455c562 100644 --- a/docs/platforms/dart/common/tracing/index.mdx +++ b/docs/platforms/dart/common/tracing/index.mdx @@ -10,30 +10,36 @@ With [tracing](/product/dashboards/sentry-dashboards/), Sentry tracks your softw -If you’re adopting Tracing in a high-throughput environment, we recommend testing prior to deployment to ensure that your service’s performance characteristics maintain expectations. +If you're adopting Tracing in a high-throughput environment, we recommend testing prior to deployment to ensure that your service's performance characteristics maintain expectations. + + + + + +Sentry can send spans in one of two ways: the default transaction mode or stream mode, where spans are streamed to Sentry as they finish. See Streamed Spans to learn more. ## Configure -First, enable tracing and configure the sample rate for transactions. Set the sample rate for your transactions by either: +First, enable tracing and configure the sample rate for transactions (or service spans in stream mode). Set the sample rate by either: -- Setting a uniform sample rate for all transactions using the option in your SDK config to a number between `0` and `1`. (For example, to send 20% of transactions, set to `0.2`.) -- Controlling the sample rate based on the transaction itself and the context in which it's captured, by providing a function to the config option. +- Setting a uniform sample rate for all transactions/service spans using the option in your SDK config to a number between `0` and `1`. (For example, to send 20% of transactions/service spans, set to `0.2`.) +- Controlling the sample rate based on the transaction/service span itself and the context in which it's captured, by providing a function to the config option. The two options are meant to be mutually exclusive. If you set both, will take precedence. -Learn more about tracing options, how to use the tracesSampler function, or how to sample transactions. +Learn more about tracing options, how to use the tracesSampler function, or how to sample transactions and service spans. ## Verify -Verify that tracing is working correctly by using our automatic instrumentation or by starting and finishing a transaction using custom instrumentation. +Verify that tracing is working correctly by using our automatic instrumentation or by starting and finishing a transaction/service span using custom instrumentation. -Test out tracing by starting and finishing a transaction, which you _must_ do so transactions can be sent to Sentry. Learn how in our Custom Instrumentation content. +Test out tracing by starting and finishing a transaction/service span, which you _must_ do so data can be sent to Sentry. Learn how in our Custom Instrumentation content. -While you're testing, set to `1.0`, as that ensures that every transaction will be sent to Sentry. Once testing is complete, you may want to set a lower value, or switch to using to selectively sample and filter your transactions, based on contextual data. +While you're testing, set to `1.0`, as that ensures that every transaction/service span will be sent to Sentry. Once testing is complete, you may want to set a lower value, or switch to using to selectively sample and filter your transactions/service spans, based on contextual data. ## Next Steps diff --git a/docs/platforms/dart/common/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/dart/common/tracing/instrumentation/automatic-instrumentation.mdx index a7678e2feb2b1..5ba428d9c082d 100644 --- a/docs/platforms/dart/common/tracing/instrumentation/automatic-instrumentation.mdx +++ b/docs/platforms/dart/common/tracing/instrumentation/automatic-instrumentation.mdx @@ -1,20 +1,26 @@ --- title: Automatic Instrumentation -description: "Learn what transactions are captured after tracing is enabled." +description: "Learn what's captured automatically after tracing is enabled." sidebar_order: 10 --- -Capturing transactions requires that you first set up tracing if you haven't already. +Automatic instrumentation requires that you first set up tracing if you haven't already. + + + + + +In stream mode, these instrumentations automatically switch to the streaming span API. No code changes are needed, except for the initial opt-in to stream mode. Learn more about Streamed Spans. ### http.Client Library Instrumentation -The `http.Client` instrumentation, once added the `SentryHttpClient` and enabled the [performance](/platforms/dart/tracing/) feature, starts a span out of the active span bound to the scope for each HTTP Request. The SDK sets the span `operation` to `http.client` and `description` to request `$METHOD $url`; for example, `GET https://sentry.io`. +The `http.Client` instrumentation, once added the `SentryHttpClient` and enabled the [performance](/platforms/dart/tracing/) feature, starts a child span of the active span for each HTTP Request. The SDK sets the span `operation` to `http.client` and `description` to request `$METHOD $url`; for example, `GET https://sentry.io`. -The span finishes once the request has been executed. The span `status` depends on either the HTTP Response `code` or `SpanStatus.internalError()` if the `code` does not match any of Sentry's `SpanStatus`. +The span finishes once the request has been executed. The span status is derived from the HTTP response code, or set to an error status if the code doesn't map to a known status. When the HTTP request throws an `Exception`, Sentry's SDK associates this exception to the running span. If you haven't set the SDK to swallow the exception and capture it, the span and `SentryEvent` will be linked when viewing it on the **Issue Details** page in sentry.io. @@ -22,9 +28,9 @@ For more information see our [SentryHttpClient integration](/platforms/dart/inte ### Dio HTTP Library Instrumentation -The Dio instrumentation starts a span out of the active span bound to the scope for each HTTP request. The SDK sets the span `operation` to `http.client` and the `description` to request `$METHOD $url`. For example, `GET https://sentry.io`. +The Dio instrumentation starts a child span of the active span for each HTTP request. The SDK sets the span `operation` to `http.client` and the `description` to request `$METHOD $url`. For example, `GET https://sentry.io`. -The span finishes once the request has been executed. The span `status` depends on either the HTTP response `code` or `SpanStatus.internalError()` if the `code` does not match any of Sentry's `SpanStatus` options. +The span finishes once the request has been executed. The span status is derived from the HTTP response code, or set to an error status if the code doesn't map to a known status. When the HTTP request throws an `Exception`, Sentry's SDK associates this exception to the running span. If you haven't set the SDK to swallow the exception and capture it, the span and `SentryEvent` will be linked when viewing it on the **Issue Details** page in [sentry.io](https://sentry.io). @@ -32,11 +38,11 @@ Learn more in our [Dio integration documentation](/platforms/dart/integrations/d ### File I/O Instrumentation -The Sentry-specific file I/O implementation starts a span out of the active span, bound to the scope for each file I/O operation. The SDK sets the span `operation` to `file.copy`, `file.write`, `file.delete`, `file.open`, `file.read` or `file.rename`, and `description` to `filename` (for example, `file.txt`). +The Sentry-specific file I/O implementation starts a child span of the active span for each file I/O operation. The SDK sets the span `operation` to `file.copy`, `file.write`, `file.delete`, `file.open`, `file.read` or `file.rename`, and `description` to `filename` (for example, `file.txt`). -In addition, the span contains other useful information such as `file.size` (raw number of bytes), `file.path` (an absolute path to the file), and `file.async` (`true` if the called method returns a `Future`, or `false` if it's a `Sync` call) as part of the `data` payload. +In addition, the span contains other useful information such as `file.size` (raw number of bytes), `file.path` (an absolute path to the file), and `file.async` (`true` if the called method returns a `Future`, or `false` if it's a `Sync` call) as additional span data. -The span finishes once the operation has been executed. The span `status` is then set to `SpanStatus.ok` if successful, or `SpanStatus.internalError` if there was an error. +The span finishes once the operation has been executed. The span status is set to a success status if it succeeds, or an error status if it fails. When the operation throws an `Exception`, Sentry's SDK associates it with the running span. If you haven't set the SDK to swallow and capture the exception, the span and `SentryEvent` will be shown as linked on the **Issue Details** page in [sentry.io](https://sentry.io). diff --git a/docs/platforms/dart/common/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/dart/common/tracing/instrumentation/custom-instrumentation.mdx index b59b1fa4dffb6..78e7a12b6c282 100644 --- a/docs/platforms/dart/common/tracing/instrumentation/custom-instrumentation.mdx +++ b/docs/platforms/dart/common/tracing/instrumentation/custom-instrumentation.mdx @@ -10,6 +10,12 @@ To capture transactions and spans customized to your organization's needs, you m + + +This page covers both transaction mode (default, using transaction) and stream mode (using service spans). See Streamed Spans to learn more. + + + diff --git a/docs/platforms/dart/common/tracing/instrumentation/performance-metrics.mdx b/docs/platforms/dart/common/tracing/instrumentation/performance-metrics.mdx index 19cd6887cfe3a..47994481e7652 100644 --- a/docs/platforms/dart/common/tracing/instrumentation/performance-metrics.mdx +++ b/docs/platforms/dart/common/tracing/instrumentation/performance-metrics.mdx @@ -1,14 +1,14 @@ --- title: Performance Metrics -description: "Learn how to attach performance metrics to your transactions." +description: "Learn how to attach performance metrics to your transactions or spans." sidebar_order: 20 --- -Sentry's SDKs support sending performance metrics data to Sentry. These are numeric values attached to transactions that are aggregated and displayed in Sentry. +Sentry's SDKs support sending performance metrics data to Sentry. These are numeric values attached to transactions or spans that are aggregated and displayed in Sentry. ## Custom Measurements -In addition to automatic performance metrics, the SDK supports custom performance measurements on transactions. +In addition to automatic performance metrics, the SDK supports custom performance measurements on transactions or spans. To set a performance measurement, you need to supply the following: diff --git a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx index 772bf1f729723..60cba660a3dfc 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/index.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -431,5 +431,4 @@ Only service spans are sampled and child spans inherit the service span's decisi To make sure you've enabled stream mode successfully: - **Check the Sentry dashboard**: Spans should appear in the Traces view shortly after each span completes, without waiting for a whole transaction to finish. Spans are buffered briefly and flushed in batches, so expect a short delay before they appear. -- **Check the envelopes**: With `options.debug = true` or network inspection, check if the span envelopes are sent with the content type `application/vnd.sentry.items.span.v2+json` instead of transaction envelopes. - **Check your logs**: If the SDK logs warnings about unsupported span operations, you may still be using the legacy Span API somewhere in your code. See the Migration Guide to update it. diff --git a/docs/platforms/dart/common/tracing/trace-propagation/custom-instrumentation/index.mdx b/docs/platforms/dart/common/tracing/trace-propagation/custom-instrumentation/index.mdx index c95628d0bcfd3..15661ec376129 100644 --- a/docs/platforms/dart/common/tracing/trace-propagation/custom-instrumentation/index.mdx +++ b/docs/platforms/dart/common/tracing/trace-propagation/custom-instrumentation/index.mdx @@ -3,4 +3,11 @@ title: Custom Instrumentation sidebar_order: 40 --- + + +This guide only applies to the default transaction mode. +In stream mode, continuing an incoming distributed trace isn't supported yet. + + + diff --git a/docs/platforms/dart/common/tracing/trace-propagation/index.mdx b/docs/platforms/dart/common/tracing/trace-propagation/index.mdx index fb41f4dd98c48..e9336106daa0c 100644 --- a/docs/platforms/dart/common/tracing/trace-propagation/index.mdx +++ b/docs/platforms/dart/common/tracing/trace-propagation/index.mdx @@ -6,6 +6,13 @@ sidebar_order: 3000 If the overall application landscape that you want to observe with Sentry consists of more than just a single service or application, distributed tracing can add a lot of value. + + +This guide only applies to the default transaction mode. +In stream mode, continuing an incoming distributed trace (from a `sentry-trace` or `baggage` header) isn't supported yet. + + + ## What is Distributed Tracing? In the context of tracing events across a distributed system, distributed tracing acts as a powerful debugging tool. Imagine your application as a vast network of interconnected parts. For example, your system might be spread across different servers or your application might split into different backend and frontend services, each potentially having their own technology stack. diff --git a/docs/platforms/dart/guides/flutter/enriching-events/transaction-name/index.mdx b/docs/platforms/dart/guides/flutter/enriching-events/transaction-name/index.mdx index 9b94a5d87abe5..fe8e4fa546af3 100644 --- a/docs/platforms/dart/guides/flutter/enriching-events/transaction-name/index.mdx +++ b/docs/platforms/dart/guides/flutter/enriching-events/transaction-name/index.mdx @@ -3,6 +3,12 @@ title: Transaction Name description: "Learn how to set or override the transaction name to capture the user and gain critical pieces of information that construct a unique identity in Sentry." --- + + +This page only applies to transaction mode. In stream mode, there's no separate transaction name — set the span name when you create it with `Sentry.startSpan('name', ...)`. See Streamed Spans for details. + + + The current transaction name is used to group transactions in our [pre-built Sentry Dashboards](/product/dashboards/sentry-dashboards/) product, as well as annotate error events with their point of failure. diff --git a/docs/platforms/dart/guides/flutter/tracing/index.mdx b/docs/platforms/dart/guides/flutter/tracing/index.mdx index 0cef16789be3a..bd4734a183ba5 100644 --- a/docs/platforms/dart/guides/flutter/tracing/index.mdx +++ b/docs/platforms/dart/guides/flutter/tracing/index.mdx @@ -10,30 +10,36 @@ With [tracing](/product/dashboards/sentry-dashboards/), Sentry tracks your softw -If you’re adopting Tracing in a high-throughput environment, we recommend testing prior to deployment to ensure that your service’s performance characteristics maintain expectations. +If you're adopting Tracing in a high-throughput environment, we recommend testing prior to deployment to ensure that your service's performance characteristics maintain expectations. + + + + + +Sentry can send spans in one of two ways: the default transaction mode or stream mode, where spans are streamed to Sentry as they finish. See Streamed Spans to learn more. ## Configure -First, enable tracing and configure the sample rate for transactions. Set the sample rate for your transactions by either: +First, enable tracing and configure the sample rate for transactions (or service spans in stream mode). Set the sample rate by either: -- Setting a uniform sample rate for all transactions using the option in your SDK config to a number between `0` and `1`. (For example, to send 20% of transactions, set to `0.2`.) -- Controlling the sample rate based on the transaction itself and the context in which it's captured, by providing a function to the config option. +- Setting a uniform sample rate for all transactions/service spans using the option in your SDK config to a number between `0` and `1`. (For example, to send 20% of transactions/service spans, set to `0.2`.) +- Controlling the sample rate based on the transaction/service span itself and the context in which it's captured, by providing a function to the config option. The two options are meant to be mutually exclusive. If you set both, will take precedence. -Learn more about tracing options, how to use the tracesSampler function, or how to sample transactions. +Learn more about tracing options, how to use the tracesSampler function, or how to sample transactions and service spans. ## Verify -Verify that tracing is working correctly by using our automatic instrumentation or by starting and finishing a transaction using custom instrumentation. +Verify that tracing is working correctly by using our automatic instrumentation or by starting and finishing a transaction/service span using custom instrumentation. -Test out tracing by starting and finishing a transaction, which you _must_ do so transactions can be sent to Sentry. Learn how in our Custom Instrumentation content. +Test out tracing by starting and finishing a transaction/service span, which you _must_ do so data can be sent to Sentry. Learn how in our Custom Instrumentation content. -While you're testing, set to `1.0`, as that ensures that every transaction will be sent to Sentry. Once testing is complete, you may want to set a lower value, or switch to using to selectively sample and filter your transactions, based on contextual data. +While you're testing, set to `1.0`, as that ensures that every transaction/service span will be sent to Sentry. Once testing is complete, you may want to set a lower value, or switch to using to selectively sample and filter your transactions/service spans, based on contextual data. ## Next Steps diff --git a/docs/platforms/dart/guides/flutter/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/dart/guides/flutter/tracing/instrumentation/automatic-instrumentation.mdx index d0cbe2d2c1fa4..a48e54f323d9d 100644 --- a/docs/platforms/dart/guides/flutter/tracing/instrumentation/automatic-instrumentation.mdx +++ b/docs/platforms/dart/guides/flutter/tracing/instrumentation/automatic-instrumentation.mdx @@ -1,12 +1,18 @@ --- title: Automatic Instrumentation -description: "Learn what transactions are captured after tracing is enabled." +description: "Learn what's captured automatically after tracing is enabled." sidebar_order: 10 --- -Capturing transactions requires that you first set up tracing if you haven't already. +Automatic instrumentation requires that you first set up tracing if you haven't already. + + + + + +In stream mode, these instrumentations automatically switch to the streaming span API. No code changes are needed, except for the initial opt-in to stream mode. Learn more about Streamed Spans. @@ -19,19 +25,19 @@ Learn more in our [Routing Instrumentation](/platforms/dart/guides/flutter/integ ### User Interaction -Sentry's user interaction instrumentation captures transactions and adds breadcrumbs for a set of different user interactions, which include clicks, long clicks, taps, and so on. +Sentry's user interaction instrumentation captures spans and adds breadcrumbs for a set of different user interactions, which include clicks, long clicks, taps, and so on. Learn more in our [User Interaction Instrumentation](/platforms/dart/guides/flutter/integrations/user-interaction-instrumentation/) docs. ### http.Client Library -Sentry's `http.Client` instrumentation captures errors and creates transaction from your HTTP requests. +Sentry's `http.Client` instrumentation captures errors and creates spans from your HTTP requests. Learn more in our [SentryHttpClient Instrumentation](/platforms/dart/integrations/http-integration/#performance-monitoring-for-http-requests) docs. ### Dio HTTP Library -Sentry's Dio instrumentation captures errors and creates transaction from your Dio HTTP requests. +Sentry's Dio instrumentation captures errors and creates spans from your Dio HTTP requests. Learn more in our [Dio Instrumentation](/platforms/dart/integrations/dio/#performance-monitoring-for-http-requests) docs. @@ -43,7 +49,7 @@ Learn more in our [App Start Instrumentation](/platforms/dart/guides/flutter/int ### Slow and Frozen Frames -Unresponsive UI and animation hitches annoy users and degrade the user experience. Two measurements to track these types of experiences are slow frames and frozen frames. If you want your app to run smoothly, you should try to avoid both. The SDK adds these two measurements for the transactions you capture. +Unresponsive UI and animation hitches annoy users and degrade the user experience. Two measurements to track these types of experiences are slow frames and frozen frames. If you want your app to run smoothly, you should try to avoid both. The SDK adds these two measurements to the traces you capture. Slow and frozen frames are Mobile Vitals, which you can learn about in the [full documentation](/product/dashboards/sentry-dashboards/mobile/mobile-vitals). diff --git a/docs/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.mdx b/docs/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.mdx index 7dcbb97cc9699..c6f514f8615b6 100644 --- a/docs/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.mdx +++ b/docs/platforms/dart/guides/flutter/tracing/instrumentation/custom-instrumentation.mdx @@ -10,6 +10,12 @@ To capture transactions and spans customized to your organization's needs, you m + + +This page covers both transaction mode (default, using transaction) and stream mode (using service spans). See Streamed Spans to learn more. + + + diff --git a/docs/platforms/dart/guides/flutter/tracing/instrumentation/performance-metrics.mdx b/docs/platforms/dart/guides/flutter/tracing/instrumentation/performance-metrics.mdx index d6ddb557a8bed..8870be2a7b19b 100644 --- a/docs/platforms/dart/guides/flutter/tracing/instrumentation/performance-metrics.mdx +++ b/docs/platforms/dart/guides/flutter/tracing/instrumentation/performance-metrics.mdx @@ -1,16 +1,16 @@ --- title: Performance Metrics -description: "Learn how to attach performance metrics to your transactions." +description: "Learn how to attach performance metrics to your transactions or spans." sidebar_order: 20 --- -Sentry's SDKs support sending performance metrics data to Sentry. These are numeric values attached to transactions that are aggregated and displayed in Sentry. +Sentry's SDKs support sending performance metrics data to Sentry. These are numeric values attached to transactions or spans that are aggregated and displayed in Sentry. ## Custom Measurements -In addition to automatic performance metrics, the SDK supports custom performance measurements on transactions. + To set a performance measurement, you need to supply the following: diff --git a/docs/platforms/dart/guides/flutter/tracing/trace-propagation/index.mdx b/docs/platforms/dart/guides/flutter/tracing/trace-propagation/index.mdx index fb41f4dd98c48..e9336106daa0c 100644 --- a/docs/platforms/dart/guides/flutter/tracing/trace-propagation/index.mdx +++ b/docs/platforms/dart/guides/flutter/tracing/trace-propagation/index.mdx @@ -6,6 +6,13 @@ sidebar_order: 3000 If the overall application landscape that you want to observe with Sentry consists of more than just a single service or application, distributed tracing can add a lot of value. + + +This guide only applies to the default transaction mode. +In stream mode, continuing an incoming distributed trace (from a `sentry-trace` or `baggage` header) isn't supported yet. + + + ## What is Distributed Tracing? In the context of tracing events across a distributed system, distributed tracing acts as a powerful debugging tool. Imagine your application as a vast network of interconnected parts. For example, your system might be spread across different servers or your application might split into different backend and frontend services, each potentially having their own technology stack. diff --git a/platform-includes/performance/add-spans-example/dart.mdx b/platform-includes/performance/add-spans-example/dart.mdx index ae5c2722b6a0a..9ec31b90e3da3 100644 --- a/platform-includes/performance/add-spans-example/dart.mdx +++ b/platform-includes/performance/add-spans-example/dart.mdx @@ -1,8 +1,9 @@ -## Add More Spans to the Transaction +## Add More Spans to the Transaction/Service Span -By default, transactions are not bound to the scope. Transaction has to be passed manually as a method parameter to enable attaching nested spans. When creating nested span, you can choose the value of `operation` and `description`. +- Transaction mode: Transactions aren't bound to the scope, so they have to be passed manually as a method parameter to attach nested spans. Keep in mind that each individual span also needs to be manually finished, and spans are sent together with their parent transaction when the transaction is finished. +- Stream mode: Nested spans attach to the active span automatically — no manual passing needed. When creating a nested span, you can choose its name and `sentry.op` (see example below). Each span ends automatically when its callback completes, and spans are streamed as they finish. -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.startTransaction('processOrderBatch()', 'task'); @@ -31,6 +32,26 @@ Future processOrderBatch(ISentrySpan span) async { } ``` -Keep in mind that each individual span also needs to be manually finished; +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; -Spans are sent together with their parent transaction when the transaction is finished. Make sure to call `finish()` on transaction once all the child spans have finished. +await Sentry.startSpan( + 'processOrderBatch()', + (span) async { + span.setAttribute('sentry.op', SentryAttribute.string('task')); + await processOrderBatch(); + }, + parentSpan: null, +); + +// No need to pass the parent span — nested spans attach to the active span. +Future processOrderBatch() async { + await Sentry.startSpan( + 'operation', + (innerSpan) async { + innerSpan.setAttribute('sentry.op', SentryAttribute.string('task')); + // omitted code + }, + ); +} +``` diff --git a/platform-includes/performance/connect-errors-spans/dart.mdx b/platform-includes/performance/connect-errors-spans/dart.mdx index 05f8821cfc70f..cd2b2d7d1cec6 100644 --- a/platform-includes/performance/connect-errors-spans/dart.mdx +++ b/platform-includes/performance/connect-errors-spans/dart.mdx @@ -2,9 +2,12 @@ Sentry errors can be linked with transactions and spans. -Errors reported to Sentry while transaction or span **bound to the scope** is running are linked automatically: +Errors reported to Sentry while a transaction or span **bound to the scope** is running are linked automatically. -```dart +- Transaction mode: Set `bindToScope: true`. +- Stream mode: The active span is bound automatically, so no flag is needed. + +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.startTransaction( @@ -22,9 +25,25 @@ try { } ``` -Exceptions may be thrown within spans that can finish before exception gets reported to Sentry. To attach span information to this exception, you must link it by calling the `throwable` setter method: +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +// The active span is bound automatically — no bindToScope needed. +await Sentry.startSpan('processOrderBatch()', (span) async { + try { + processOrderBatch(); + } catch (exception) { + Sentry.captureException(exception); + } +}); +``` + +Exceptions may be thrown within spans that can finish before the exception gets reported to Sentry. + +- Transaction mode: Link it by calling the `throwable` setter. +- Stream mode: An exception thrown inside the callback is recorded on the span and rethrown automatically. -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.startTransaction('processOrderBatch()', 'task'); @@ -38,3 +57,12 @@ try { await transaction.finish(); } ``` + +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +// If the callback throws, the span is marked as errored and the error is rethrown. +await Sentry.startSpan('processOrderBatch()', (span) async { + processOrderBatch(); +}); +``` diff --git a/platform-includes/performance/custom-performance-metrics/dart.mdx b/platform-includes/performance/custom-performance-metrics/dart.mdx index 7de13e1a3e93a..ae6962bb0385f 100644 --- a/platform-includes/performance/custom-performance-metrics/dart.mdx +++ b/platform-includes/performance/custom-performance-metrics/dart.mdx @@ -1,6 +1,11 @@ Adding custom measurements is supported in Sentry's Dart/Flutter SDK version `6.11.0` and above. -```dart +- Transaction mode (default): Use `setMeasurement` on the active span. +- Stream mode: There's + no dedicated measurement API (and no public way to fetch the active span), so + record the values as attributes on a span you create. + +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.getSpan(); @@ -16,3 +21,14 @@ transaction?.setMeasurement('ui.footerComponent.render', 1.3, // Record amount of times localStorage was read transaction?.setMeasurement('localStorageRead', 4); ``` + +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +await Sentry.startSpan('my-operation', (span) async { + // Record custom measurements as span attributes. + span.setAttribute('memoryUsed', SentryAttribute.int(123)); + span.setAttribute('ui.footerComponent.render', SentryAttribute.double(1.3)); + span.setAttribute('localStorageRead', SentryAttribute.int(4)); +}); +``` diff --git a/platform-includes/performance/enable-manual-instrumentation/dart.mdx b/platform-includes/performance/enable-manual-instrumentation/dart.mdx index 18c0931947310..f58288eccb0c2 100644 --- a/platform-includes/performance/enable-manual-instrumentation/dart.mdx +++ b/platform-includes/performance/enable-manual-instrumentation/dart.mdx @@ -1,8 +1,8 @@ -To instrument certain regions of your code, you can create transactions to capture them. +To instrument certain regions of your code, you can create a transaction (or a service span in stream mode) to capture them. -The following example creates a transaction that contains an expensive operation (for example, `processOrderBatch`), and sends the result to Sentry: +The following example creates a transaction/service span that contains an expensive operation (for example, `processOrderBatch`), and sends the result to Sentry: -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.startTransaction('processOrderBatch()', 'task'); @@ -16,3 +16,18 @@ try { await transaction.finish(); } ``` + +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +// Pass parentSpan: null to force a new service span. +// The status is set to error automatically if the callback throws. +await Sentry.startSpan( + 'processOrderBatch()', + (span) async { + span.setAttribute('sentry.op', SentryAttribute.string('task')); + processOrderBatch(); + }, + parentSpan: null, +); +``` diff --git a/platform-includes/performance/improving-data/dart.mdx b/platform-includes/performance/improving-data/dart.mdx index 0a4b0e6e9fc44..f7cbbd61a03bc 100644 --- a/platform-includes/performance/improving-data/dart.mdx +++ b/platform-includes/performance/improving-data/dart.mdx @@ -1,10 +1,13 @@ ## Adding Data Attributes to Transactions and Spans -You can add data attributes to your transactions and spans. This data is visible in the trace explorer in Sentry. Data attributes can be of type `String`, `int`, `double` or `bool`, as well as (non-mixed) arrays of these types: +You can add data attributes to your transactions and spans. This data is visible in the trace explorer in Sentry. -### For Transactions +- Transaction mode: Use `setData` with `String`, `int`, `double` or `bool` values, as well as (non-mixed) arrays of these types. +- Stream mode: Use `setAttribute` or `setAttributes` with a typed `SentryAttribute` factory. -```dart +### For Transactions/Service Spans + +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} final transaction = Sentry.startTransaction('my-transaction', 'http.server'); transaction.setData('data_attribute_1', 'value1'); transaction.setData('data_attribute_2', 42); @@ -15,9 +18,29 @@ transaction.setData('data_attribute_5', [42, 43]); transaction.setData('data_attribute_6', [true, false]); ``` +```dart {tabTitle:Stream Mode} +await Sentry.startSpan( + 'my-transaction', + (span) async { + span.setAttribute('sentry.op', SentryAttribute.string('http.server')); + span.setAttribute('data_attribute_1', SentryAttribute.string('value1')); + span.setAttribute('data_attribute_2', SentryAttribute.int(42)); + span.setAttribute('data_attribute_3', SentryAttribute.bool(true)); + + span.setAttributes({ + 'data_attribute_4': SentryAttribute.stringArray(['value1', 'value2']), + 'data_attribute_5': SentryAttribute.intArray([42, 43]), + 'data_attribute_6': SentryAttribute.boolArray([true, false]) + }); + }, + // force the creation of a service span + parentSpan: null, +); +``` + ### For Spans -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} final span = parent.startChild('http.client'); span.setData('data_attribute_1', 'value1'); span.setData('data_attribute_2', 42); @@ -27,3 +50,17 @@ span.setData('data_attribute_4', ['value1', 'value2']); span.setData('data_attribute_5', [42, 43]); span.setData('data_attribute_6', [true, false]); ``` + +```dart {tabTitle:Stream Mode} +await Sentry.startSpan('http.client', (span) async { + span.setAttribute('data_attribute_1', SentryAttribute.string('value1')); + span.setAttribute('data_attribute_2', SentryAttribute.int(42)); + span.setAttribute('data_attribute_3', SentryAttribute.bool(true)); + + span.setAttributes({ + 'data_attribute_4': SentryAttribute.stringArray(['value1', 'value2']), + 'data_attribute_5': SentryAttribute.intArray([42, 43]), + 'data_attribute_6': SentryAttribute.boolArray([true, false]) + }); +}); +``` diff --git a/platform-includes/performance/retrieve-transaction/dart.mdx b/platform-includes/performance/retrieve-transaction/dart.mdx index 9a1a75aa818d4..e095b4b699e3d 100644 --- a/platform-includes/performance/retrieve-transaction/dart.mdx +++ b/platform-includes/performance/retrieve-transaction/dart.mdx @@ -1,8 +1,9 @@ -## Retrieve a Transaction +## Retrieve a Transaction/Service Span -In cases where you want to attach Spans to an already ongoing Transaction you can use `Sentry#getSpan`. This method will return a `SentryTransaction` in case there is a running Transaction, otherwise it returns `null`. +- Transaction mode: When you want to attach spans to an already ongoing transaction, use `Sentry.getSpan()`. It returns the running `SentryTransaction`, or `null` if there is none. +- Stream Mode: There's no public API to retrieve the active span. You don't need one: `Sentry.startSpan` attaches to the currently active span automatically, or starts a new service span if none is active. -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final span = Sentry.getSpan()?.startChild('task') ?? @@ -17,3 +18,12 @@ try { await span.finish(); } ``` + +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +// Attaches to the active span, or starts a new service span if none is active. +await Sentry.startSpan('task', (span) async { + processOrderBatch(); +}); +``` From ec47a899514dbe957d6f255d33c5d973cf34ec34 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 20 Jul 2026 10:41:00 +0200 Subject: [PATCH 13/14] docs(dart): Document stream mode in integration guides (#18610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## DESCRIBE YOUR PR Documents **stream mode** across the Dart/Flutter integration guides. - Adds a reusable stream-mode callout to every integration page (transactions become service spans; auto-instrumentation switches automatically) - Adds inline `// or, in stream mode: Sentry.startSpan(...)` hints next to the transaction/span creation in the integration code snippets (http, dio, file, graphql, sqflite, drift, hive, isar, asset bundle, user interaction), mirroring the Python integrations approach Stacked on #18554 — review/merge that first. Ref: https://github.com/getsentry/sentry-dart/issues/3886 ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. - [ ] Urgent deadline (GA date, etc.): - [ ] Other deadline: - [x] None: Not urgent, can wait up to 1 week+ ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it. Thanks in advance for your help! ## PRE-MERGE CHECKLIST *Make sure you've checked the following before merging your changes:* - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) --------- Co-authored-by: Claude Co-authored-by: inventarSarah --- .../app-start-instrumentation.mdx | 2 + .../asset-bundle-instrumentation.mdx | 6 +++ includes/dart-integrations/dio.mdx | 24 +++++++++- .../drift-instrumentation.mdx | 34 ++++++++++++- includes/dart-integrations/file.mdx | 48 ++++++++++++++++++- includes/dart-integrations/graphql.mdx | 40 +++++++++++----- .../hive-instrumentation.mdx | 25 +++++++++- .../dart-integrations/http-integration.mdx | 22 ++++++++- includes/dart-integrations/index.mdx | 2 + .../isar-instrumentation.mdx | 39 ++++++++++++++- .../routing-instrumentation.mdx | 2 + ...slow-and-frozen-frames-instrumentation.mdx | 2 + .../sqflite-instrumentation.mdx | 39 ++++++++++++++- .../user-interaction-instrumentation.mdx | 20 +++++++- includes/dart-stream-mode-general-callout.mdx | 5 ++ 15 files changed, 283 insertions(+), 27 deletions(-) create mode 100644 includes/dart-stream-mode-general-callout.mdx diff --git a/includes/dart-integrations/app-start-instrumentation.mdx b/includes/dart-integrations/app-start-instrumentation.mdx index 2212c45a5872e..bf81d171b5df4 100644 --- a/includes/dart-integrations/app-start-instrumentation.mdx +++ b/includes/dart-integrations/app-start-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + Sentry's app start instrumentation provides insight into how long your application takes to launch. diff --git a/includes/dart-integrations/asset-bundle-instrumentation.mdx b/includes/dart-integrations/asset-bundle-instrumentation.mdx index ed9e6c822c204..9c578e24dd7c1 100644 --- a/includes/dart-integrations/asset-bundle-instrumentation.mdx +++ b/includes/dart-integrations/asset-bundle-instrumentation.mdx @@ -10,6 +10,12 @@ platforms: - flutter --- + + +Asset bundle instrumentation isn't supported in stream mode yet — it creates spans only in the default transaction mode. + + + [AssetBundle](https://api.flutter.dev/flutter/services/AssetBundle-class.html) instrumentation provides insight into how long your app takes to load its assets, such as files. ## Instrumentation Behaviour diff --git a/includes/dart-integrations/dio.mdx b/includes/dart-integrations/dio.mdx index f0e161c09b29e..85a444a2c0a27 100644 --- a/includes/dart-integrations/dio.mdx +++ b/includes/dart-integrations/dio.mdx @@ -7,6 +7,8 @@ platforms: sidebar_order: 4 --- + + The `sentry_dio` library provides [Dio](https://pub.dev/packages/dio) support for Sentry using the [HttpClientAdapter](https://pub.dev/documentation/dio/latest/dio/HttpClientAdapter-class.html). It is able to collect breadcrumbs, run tracing for HTTP requests, and capture events for failed requests. ## Install @@ -121,7 +123,7 @@ The Dio integration also provides insight into tracing for your HTTP requests do ### Instrumentation Behaviour -- The created spans will be attached to the transaction on the scope - if no transaction is on the scope the span will not be sent to Sentry. +- The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the span won't be sent to Sentry. - The SDK sets the span operation to `http.client` and the description to request `$METHOD $url`. For example, `GET https://sentry.io`. - The span finishes once the request has been executed. - The span status depends on either the HTTP response code or `SpanStatus.internalError()` if the code does not match any of Sentry's SpanStatus options. @@ -150,7 +152,7 @@ dio.addSentry(); #### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry_dio/sentry_dio.dart'; Future makeWebRequestWithDio() async { @@ -181,6 +183,24 @@ Future makeWebRequestWithDio() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:sentry_dio/sentry_dio.dart'; + +Future makeWebRequestWithDio() async { + final dio = Dio(); + dio.addSentry(); + + // Start a root span — the Dio integration attaches a span for the request + await Sentry.startSpan('dio-web-request', (span) async { + try { + final response = await dio.get(exampleUrl); + } catch (exception, stackTrace) { + await Sentry.captureException(exception, stackTrace: stackTrace); + } + }, parentSpan: null); +} +``` + #### 2. View the Transaction on Sentry.io To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. diff --git a/includes/dart-integrations/drift-instrumentation.mdx b/includes/dart-integrations/drift-instrumentation.mdx index b5a7fd68ae984..ac3bb1bfe2f10 100644 --- a/includes/dart-integrations/drift-instrumentation.mdx +++ b/includes/dart-integrations/drift-instrumentation.mdx @@ -10,12 +10,14 @@ platforms: - flutter --- + + Drift is a library for easily managing SQLite databases within Flutter applications. The [sentry_drift](https://pub.dev/packages/sentry_drift) package provides `Drift` support for database performance instrumentation and allows you to track the performance of your queries. ## Instrumentation Behaviour -The created spans will be attached to the transaction on the scope - if no transaction is on the scope the Drift span will not be sent to Sentry. +The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the Drift span won't be sent to Sentry. ## Prerequisites @@ -60,7 +62,7 @@ await database.runWithInterceptor(interceptor: interceptor, () async { ### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:sentry/sentry.dart'; @@ -93,6 +95,34 @@ Future driftTest() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:sentry/sentry.dart'; +import 'package:sentry_drift/sentry_drift.dart'; + +import 'your_database.dart'; + +Future driftTest() async { + await Sentry.startSpan('driftTest', (span) async { + final interceptor = SentryQueryInterceptor(databaseName: 'my_database_name'); + final executor = inMemoryExecutor().interceptWith(interceptor); + final db = AppDatabase(executor); + + await db.into(db.todoItems).insert( + TodoItemsCompanion.insert( + title: 'This is a test title', + content: 'test', + ), + ); + + final items = await db.select(db.todoItems).get(); + + await db.close(); + }, parentSpan: null); +} +``` + ### 2. View the Transaction on Sentry.io To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. diff --git a/includes/dart-integrations/file.mdx b/includes/dart-integrations/file.mdx index 57ff19c7708f6..80a7c9bade763 100644 --- a/includes/dart-integrations/file.mdx +++ b/includes/dart-integrations/file.mdx @@ -7,12 +7,14 @@ platforms: - flutter --- + + File I/O operations are fundamental for reading from and writing to files within an application. The `sentry_file` integration provides [File](https://api.dart.dev/stable/2.18.5/dart-io/File-class.html) support for Sentry thus providing insight into tracing of file operations. ## Behavior -- The created spans will be attached to the transaction on the scope - if no transaction is on the scope the File I/O span will not be sent to Sentry. +- The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the File I/O span won't be sent to Sentry. - The File I/O integration is only available for the `dart:io:File` class, not for the `dart:html:File` class. - The SDK sets the span `operation` to `file.copy`, `file.write`, `file.delete`, `file.open`, `file.read` or `file.rename`, and `description` to `filename` (for example, `file.txt`). - The span finishes once the operation has been executed. The span `status` is then set to `SpanStatus.ok` if successful, or `SpanStatus.internalError` if there was an error. @@ -45,7 +47,7 @@ final sentryFile = file.sentryTrace(); ### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; import 'package:sentry_file/sentry_file.dart'; import 'dart:io'; @@ -92,6 +94,48 @@ Future runApp() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; +import 'package:sentry_file/sentry_file.dart'; +import 'dart:io'; + +Future main() async { + await Sentry.init( + (options) { + options.dsn = 'https://example@sentry.io/example'; + // To set a uniform sample rate + options.tracesSampleRate = 1.0; + // Enables stream mode + options.traceLifecycle = SentryTraceLifecycle.stream; + }, + appRunner: runApp, // Init your App. + ); +} + +Future runApp() async { + final file = File('my_file.txt'); + // Call the Sentry extension method to wrap up the File + final sentryFile = file.sentryTrace(); + + // Start a root span — file I/O spans attach to the active span + await Sentry.startSpan('MyFileExample', (span) async { + // create the File + await sentryFile.create(); + // Write some content + await sentryFile.writeAsString('Hello World'); + // Read the content + final text = await sentryFile.readAsString(); + + print(text); + + // Delete the file + await sentryFile.delete(); + }, parentSpan: null); + + await Sentry.close(); +} +``` + ### 2. View the Recorded Transaction on Sentry.io To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. diff --git a/includes/dart-integrations/graphql.mdx b/includes/dart-integrations/graphql.mdx index 00ef3989eff2e..f9aad81c43c01 100644 --- a/includes/dart-integrations/graphql.mdx +++ b/includes/dart-integrations/graphql.mdx @@ -7,6 +7,8 @@ platforms: - flutter --- + + The `sentry_link` integration adds Sentry instrumentation to GraphQL clients built on the [gql](https://pub.dev/packages/gql) ecosystem. It helps you capture: @@ -78,15 +80,15 @@ For better error context and grouping, add the recommended init options from [Ad ## `SentryGql.link()` Options -| Parameter | Type | Default | Description | -| --- | --- | --- | --- | -| `shouldStartTransaction` | `bool` | _required_ | Set to `true` to start a transaction per GraphQL operation when no active span/transaction exists. | -| `graphQlErrorsMarkTransactionAsFailed` | `bool` | _required_ | Set to `true` to mark GraphQL spans/transactions as `unknownError` when `response.errors` exists. | -| `enableBreadcrumbs` | `bool` | `true` | Records breadcrumbs for successful GraphQL operations. | -| `reportExceptions` | `bool` | `true` | Captures `LinkException` failures as Sentry events. | -| `reportExceptionsAsBreadcrumbs` | `bool` | `false` | Records `LinkException` failures as breadcrumbs instead of events. | -| `reportGraphQlErrors` | `bool` | `true` | Captures GraphQL response errors as Sentry events. | -| `reportGraphQlErrorsAsBreadcrumbs` | `bool` | `false` | Records GraphQL response errors as breadcrumbs instead of events. | +| Parameter | Type | Default | Description | +| -------------------------------------- | ------ | ---------- | -------------------------------------------------------------------------------------------------- | +| `shouldStartTransaction` | `bool` | _required_ | Set to `true` to start a transaction per GraphQL operation when no active span/transaction exists. | +| `graphQlErrorsMarkTransactionAsFailed` | `bool` | _required_ | Set to `true` to mark GraphQL spans/transactions as `unknownError` when `response.errors` exists. | +| `enableBreadcrumbs` | `bool` | `true` | Records breadcrumbs for successful GraphQL operations. | +| `reportExceptions` | `bool` | `true` | Captures `LinkException` failures as Sentry events. | +| `reportExceptionsAsBreadcrumbs` | `bool` | `false` | Records `LinkException` failures as breadcrumbs instead of events. | +| `reportGraphQlErrors` | `bool` | `true` | Captures GraphQL response errors as Sentry events. | +| `reportGraphQlErrorsAsBreadcrumbs` | `bool` | `false` | Records GraphQL response errors as breadcrumbs instead of events. | ## Error Reporting Layers @@ -381,6 +383,14 @@ final link = Link.from([ ), ]); +Map? _defaultHttpResponseDecoder(http.Response response) { + return json.decode(utf8.decode(response.bodyBytes)) as Map?; +} +``` + +The decoder itself creates the span. In transaction mode, it starts a child off the currently active transaction. In stream mode, `Sentry.startSpanSync()` is used instead, which attaches the new span to the currently active span automatically and sets its status based on whether the callback throws: + +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} Map? sentryResponseDecoder( http.Response response, { Hub? hub, @@ -403,9 +413,17 @@ Map? sentryResponseDecoder( } return result; } +``` -Map? _defaultHttpResponseDecoder(http.Response response) { - return json.decode(utf8.decode(response.bodyBytes)) as Map?; +```dart {tabTitle:Stream Mode} +Map? sentryResponseDecoder( + http.Response response, { + Hub? hub, +}) { + return Sentry.startSpanSync( + 'serialize.http.client', + (span) => _defaultHttpResponseDecoder(response), + ); } ``` diff --git a/includes/dart-integrations/hive-instrumentation.mdx b/includes/dart-integrations/hive-instrumentation.mdx index 8568aa56274cb..6f82a6b2d0e5c 100644 --- a/includes/dart-integrations/hive-instrumentation.mdx +++ b/includes/dart-integrations/hive-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + _(New in version 7.13.1)_ @@ -19,7 +21,7 @@ The [sentry_hive](https://pub.dev/packages/sentry_hive) package provides `Hive` ## Instrumentation Behaviour -The created spans will be attached to the transaction on the scope - if no transaction is on the scope the Hive span will not be sent to Sentry. +The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the Hive span won't be sent to Sentry. ## Prerequisites @@ -55,7 +57,7 @@ SentryHive.init(appDir.path); ### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry_hive/sentry_hive.dart'; Future hiveTest() async { @@ -80,6 +82,25 @@ Future hiveTest() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:sentry_hive/sentry_hive.dart'; + +Future hiveTest() async { + await Sentry.startSpan('hiveTest', (span) async { + final appDir = await getApplicationDocumentsDirectory(); + SentryHive.init(appDir.path); + + final catsBox = await SentryHive.openBox('cats'); + await catsBox.put('fluffy', {'name': 'Fluffy', 'age': 4}); + await catsBox.put('loki', {'name': 'Loki', 'age': 2}); + await catsBox.clear(); + await catsBox.close(); + + SentryHive.close(); + }, parentSpan: null); +} +``` + ### 2. View the Transaction on Sentry.io To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. diff --git a/includes/dart-integrations/http-integration.mdx b/includes/dart-integrations/http-integration.mdx index 90df7dda92e24..c7b9f4d6259f3 100644 --- a/includes/dart-integrations/http-integration.mdx +++ b/includes/dart-integrations/http-integration.mdx @@ -7,6 +7,8 @@ platforms: - flutter --- + + ## Using the `SentryHttpClient` function You can use the `SentryHttpClient` and call its methods directly, or you can use it with the [`runWithClient`](https://pub.dev/documentation/http/latest/http/runWithClient.html) function. If you need to use a fresh instance of the `client` (so that other instances are not affected) or to run in a separate [`Zone`](https://api.dart.dev/stable/3.5.0/dart-async/Zone-class.html), which allows you to override the functionality of the existing [`Zone`](https://api.dart.dev/stable/3.5.0/dart-async/Zone-class.html), then use the `runWithClient` function (see the `runWithClient` tab). Otherwise, just use `SentryHttpClient` directly and call its methods (see the `default` tab). @@ -184,9 +186,9 @@ Capturing transactions requires that you first set -The `SentryHttpClient` starts a span out of the active span bound to the scope for each HTTP Request. +The `SentryHttpClient` starts a span off the active span for each HTTP request. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry/sentry.dart'; final transaction = Sentry.startTransaction( @@ -206,3 +208,19 @@ try { await transaction.finish(status: SpanStatus.ok()); ``` + +```dart {tabTitle:Stream Mode} +import 'package:sentry/sentry.dart'; + +// Start a root span — a span is attached for each HTTP request +await Sentry.startSpan('webrequest', (span) async { + var client = SentryHttpClient(); + try { + var uriResponse = await client.post('https://example.com/whatsit/create', + body: {'name': 'doodle', 'color': 'blue'}); + print(await client.get(uriResponse.bodyFields['uri'])); + } finally { + client.close(); + } +}, parentSpan: null); +``` diff --git a/includes/dart-integrations/index.mdx b/includes/dart-integrations/index.mdx index 597a16c57ac38..0faf6b3afb3eb 100644 --- a/includes/dart-integrations/index.mdx +++ b/includes/dart-integrations/index.mdx @@ -1,3 +1,5 @@ + + | **Integration** | **Auto
Enabled** | **Errors** | **Tracing** | **Additional
Context** | | ----------------------------------------------------- | :--------------: | :--------: | :---------: | :--------------------: | diff --git a/includes/dart-integrations/isar-instrumentation.mdx b/includes/dart-integrations/isar-instrumentation.mdx index 538ca3cdf2884..280a6ef1ad09e 100644 --- a/includes/dart-integrations/isar-instrumentation.mdx +++ b/includes/dart-integrations/isar-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + _(New in version 7.16.0)_ @@ -19,7 +21,7 @@ The [sentry_isar](https://pub.dev/packages/sentry_isar) package provides `Isar` ## Instrumentation Behaviour -The created spans will be attached to the transaction on the scope. If no transaction is on the scope the Isar span will not be sent to Sentry. +The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the Isar span won't be sent to Sentry. ## Prerequisites @@ -61,7 +63,7 @@ final isar = await SentryIsar.open( ### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:path_provider/path_provider.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_isar/sentry_isar.dart'; @@ -96,6 +98,39 @@ Future runApp() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:path_provider/path_provider.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_isar/sentry_isar.dart'; + +import 'user.dart'; // Import your Isar model instead + +Future runApp() async { + await Sentry.startSpan('isarTest', (span) async { + final dir = await getApplicationDocumentsDirectory(); + + final isar = await SentryIsar.open( + [UserSchema], + directory: dir.path, + ); + + final newUser = User() + ..name = 'Joe Dirt' + ..age = 36; + + await isar.writeTxn(() async { + await isar.users.put(newUser); // insert & update + }); + + final existingUser = await isar.users.get(newUser.id); // get + + await isar.writeTxn(() async { + await isar.users.delete(existingUser!.id); // delete + }); + }, parentSpan: null); +} +``` + ### 2. View the Transaction on Sentry.io To view the recorded transaction, log into [sentry.io](https://sentry.io). Use the left sidebar to navigate to the **Performance** page. Select your project and scroll down to the transactions table to see the just recorded transaction with the name `isarTest`. You can also use the search bar to find the transaction. Click on the transaction to open its **Transaction Summary** page for more performance details. diff --git a/includes/dart-integrations/routing-instrumentation.mdx b/includes/dart-integrations/routing-instrumentation.mdx index a77406e697b44..2fdc67e23d51a 100644 --- a/includes/dart-integrations/routing-instrumentation.mdx +++ b/includes/dart-integrations/routing-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + Sentry's routing instrumentation for Flutter automatically tracks and reports page navigation events in your app. It supports imperative navigation (`Navigator.push()`), the declarative `Router` API (`MaterialApp.router`), and popular routing packages like [GoRouter](https://pub.dev/packages/go_router) and [auto_route](https://pub.dev/packages/auto_route). diff --git a/includes/dart-integrations/slow-and-frozen-frames-instrumentation.mdx b/includes/dart-integrations/slow-and-frozen-frames-instrumentation.mdx index 00183212386a3..bceaec6a7a907 100644 --- a/includes/dart-integrations/slow-and-frozen-frames-instrumentation.mdx +++ b/includes/dart-integrations/slow-and-frozen-frames-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + Unresponsive UI and animation hitches annoy users and degrade the user experience. This integration can help. Set it up and identify these problems in your app by tracking and showing **slow frames**, **frozen frames**, and **frame delay** metrics for spans. Learn more about frame delay [here](https://develop.sentry.dev/sdk/performance/frames-delay/). diff --git a/includes/dart-integrations/sqflite-instrumentation.mdx b/includes/dart-integrations/sqflite-instrumentation.mdx index 94e8a34a5cefb..0b068609aedfa 100644 --- a/includes/dart-integrations/sqflite-instrumentation.mdx +++ b/includes/dart-integrations/sqflite-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + _(New in version 7.2.0)_ @@ -18,7 +20,7 @@ The [sentry_sqflite](https://pub.dev/packages/sentry_sqflite) package provides ` ## Instrumentation Behaviour -- The created spans will be attached to the transaction on the scope - if no transaction is on the scope the sqflite span will not be sent to Sentry. +- The created spans attach to the active span. In transaction mode, that's the transaction bound to the scope; in stream mode, it's the span started with `Sentry.startSpan()`. If no span is active, the sqflite span won't be sent to Sentry. - The spans' `operation` are either `db`, `db.sql.execute`, `db.sql.query` or `db.sql.transaction`. Its `description` is the SQL statement using placeholders instead of its values due to the possibility of containing PII. ## Prerequisites @@ -94,7 +96,7 @@ final sentryDatabase = SentryDatabase(database); ### 1. Execute the Code -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} import 'package:sentry_sqflite/sentry_sqflite.dart'; import 'package:sqflite/sqflite.dart'; @@ -133,6 +135,39 @@ Future sqfliteTest() async { } ``` +```dart {tabTitle:Stream Mode} +import 'package:sentry_sqflite/sentry_sqflite.dart'; +import 'package:sqflite/sqflite.dart'; + +Future sqfliteTest() async { + await Sentry.startSpan('sqfliteTest', (span) async { + // You can also use the other configuration methods + final db = await openDatabaseWithSentry(inMemoryDatabasePath); + + await db.execute('''CREATE TABLE Product (id INTEGER PRIMARY KEY,title TEXT)'''); + final dbTitles = []; + for (int i = 1; i <= 20; i++) { + final title = 'Product $i'; + dbTitles.add(title); + await db.insert('Product', {'title': title}); + } + + await db.query('Product'); + + await db.transaction((txn) async { + await txn + .insert('Product', {'title': 'Product Another one'}); + await txn.delete('Product', + where: 'title = ?', whereArgs: ['Product Another one']); + }); + + await db.delete('Product', where: 'title = ?', whereArgs: ['Product 1']); + + await db.close(); + }, parentSpan: null); +} +``` + ### 2. View the Transaction on Sentry To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project (via main navigation menu Dashboards). diff --git a/includes/dart-integrations/user-interaction-instrumentation.mdx b/includes/dart-integrations/user-interaction-instrumentation.mdx index 2c95fc3c8a326..acfb12b0dfcc4 100644 --- a/includes/dart-integrations/user-interaction-instrumentation.mdx +++ b/includes/dart-integrations/user-interaction-instrumentation.mdx @@ -10,6 +10,8 @@ platforms: - flutter --- + + _(New in version 6.17.0)_ Enabling UI instrumentation captures transactions and adds breadcrumbs for a set of different user interactions, which include clicks, long clicks, taps, and so on. @@ -50,7 +52,7 @@ Future main() async { If the view doesn't have the key assigned, the transaction and the breadcrumb won't be captured because it can't be uniquely identified. The key value should be unique across the whole application because the transactions are grouped by its name. -```dart +```dart {tabTitle:Transaction Mode (Default)} {mdExpandTabs} ElevatedButton( key: const Key('my_button_widget'), onPressed: () { @@ -61,6 +63,18 @@ ElevatedButton( ), ``` +```dart {tabTitle:Stream Mode} +ElevatedButton( + key: const Key('my_button_widget'), + onPressed: () async { + // The tap starts a root span automatically; nested spans attach to it + await Sentry.startSpan('some operation', (span) async { + // your operation + }); + }, child: const Text('User Interaction Example'), +), +``` + ## Verify Tap on the button specified in step 2 of the configure section, wait for `idleTimeout` seconds (default is 3s) then check the performance page for a new transaction called `my_button_widget`. @@ -141,7 +155,9 @@ The `idleTimeoout` defaults to `3000` milliseconds (3 seconds). You can also disable the idle timeout by setting it to `null`, but if you do, you must finish the transaction manually. -To finish the transaction manually, use `Sentry.getSpan()` to retrieve the active transaction on the scope: +In stream mode, there's no public accessor for the active span, so manual finishing isn't available — keep the idle timeout enabled so the span finishes automatically. + +To finish the transaction manually in transaction mode, use `Sentry.getSpan()` to retrieve the active transaction on the scope: ```dart import 'package:sentry/sentry.dart'; diff --git a/includes/dart-stream-mode-general-callout.mdx b/includes/dart-stream-mode-general-callout.mdx new file mode 100644 index 0000000000000..c6229e9efda80 --- /dev/null +++ b/includes/dart-stream-mode-general-callout.mdx @@ -0,0 +1,5 @@ + + +References to "transactions" on this page apply to the default transaction mode. In stream mode, transactions become service spans that stream as they finish. See Streamed Spans for more information. + + From c898c62ad1aa8158172cd41ac38d5cd8ebb3bd91 Mon Sep 17 00:00:00 2001 From: Giancarlo Buenaflor Date: Mon, 20 Jul 2026 10:41:19 +0200 Subject: [PATCH 14/14] docs(dart): Document stream mode in configuration pages (#18609) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## DESCRIBE YOUR PR Documents **stream mode** across the Dart/Flutter configuration pages. - `options.mdx`: new `traceLifecycle`, `beforeSendSpan`, and `ignoreSpans` options (both Dart and Flutter) - `filtering.mdx`: a "Filtering Spans in Stream Mode" section (`ignoreSpans` + `beforeSendSpan`) - `sampling.mdx`: notes that a custom `tracesSampler` receives a span sampling context in stream mode, and that custom sampling context / forcing a decision don't apply - Stream-mode notes in sensitive-data and profiling Stacked on #18554 — review/merge that first. Ref: https://github.com/getsentry/sentry-dart/issues/3886 ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. - [ ] Urgent deadline (GA date, etc.): - [ ] Other deadline: - [x] None: Not urgent, can wait up to 1 week+ ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it. Thanks in advance for your help! ## PRE-MERGE CHECKLIST *Make sure you've checked the following before merging your changes:* - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) --------- Co-authored-by: Claude Co-authored-by: inventarSarah --- .../dart/common/configuration/filtering.mdx | 76 +++++++++++++++-- .../dart/common/configuration/options.mdx | 68 +++++++++++++++ .../dart/common/configuration/sampling.mdx | 51 ++++++++---- .../data-management/sensitive-data/index.mdx | 6 +- .../streamed-spans/migration-guide.mdx | 19 ++++- .../flutter/configuration/filtering.mdx | 82 +++++++++++++++++-- .../guides/flutter/configuration/options.mdx | 68 +++++++++++++++ .../guides/flutter/configuration/sampling.mdx | 49 +++++++---- .../data-management/sensitive-data/index.mdx | 6 +- .../dart/guides/flutter/profiling/index.mdx | 2 - .../before-send-transaction/dart.flutter.mdx | 11 +++ .../before-send-transaction/dart.mdx | 11 +++ .../ignore-transactions/dart.flutter.mdx | 5 ++ .../ignore-transactions/dart.mdx | 2 +- .../sampling-function-intro/dart.flutter.mdx | 4 +- .../sampling-function-intro/dart.mdx | 4 +- .../dart.flutter.mdx | 14 +++- .../traces-sampler-as-sampler/dart.mdx | 14 +++- .../uniform-sample-rate/dart.flutter.mdx | 2 +- .../performance/uniform-sample-rate/dart.mdx | 2 +- 20 files changed, 430 insertions(+), 66 deletions(-) create mode 100644 platform-includes/configuration/before-send-transaction/dart.flutter.mdx create mode 100644 platform-includes/configuration/before-send-transaction/dart.mdx create mode 100644 platform-includes/configuration/ignore-transactions/dart.flutter.mdx diff --git a/docs/platforms/dart/common/configuration/filtering.mdx b/docs/platforms/dart/common/configuration/filtering.mdx index 10fac3931ca5a..1aba8224c08cc 100644 --- a/docs/platforms/dart/common/configuration/filtering.mdx +++ b/docs/platforms/dart/common/configuration/filtering.mdx @@ -42,7 +42,8 @@ When the SDK creates an event or breadcrumb for transmission, that transmission Hints are available in two places: -1. / +1. / + 2. `eventProcessors` Event and breadcrumb `hints` are objects containing various information used to put together an event or a breadcrumb. Typically `hints` hold the original exception so that additional data can be extracted or grouping can be affected. @@ -71,26 +72,85 @@ When a string or a non-error object is raised, Sentry creates a synthetic except -## Filtering Transaction Events +## Filtering Transactions and Spans -To prevent certain transactions from being reported to Sentry, use the or configuration option, which allows you to provide a function to evaluate the current transaction and drop it if it's not one you want. +Use to make a sampling decision when a transaction or service span starts. Return `0` to drop it. + +In transaction mode, use to drop transactions by name or to modify or drop them with custom logic. In stream mode, use to drop spans by name or to modify them. ### Using -You can use the option to filter out transactions that match a certain pattern. This option receives a list of strings and regular expressions to match against the transaction name. When using strings, partial matches will be filtered out. If you need to filter by exact match, use regex patterns instead. + + +Not available in stream mode. Use instead. + + + +You can use the option to filter out transactions that match a certain pattern. This option receives a list of string patterns, treats them as case-insensitive regular expressions, and matches them against the transaction name. Patterns match substrings by default. Use `^` and `$` to match the full transaction name. +### Using + + + +Only available in transaction mode. In stream mode, use to modify spans and to drop them. + + + +Use the callback to modify or drop a transaction immediately before it's sent. Return the transaction to send it, or return `null` to drop it. + + + +### Using + + + +Only available in stream mode. + + + +Use the configuration option to modify a span. It runs when each span ends. + +If you want to drop spans, use [](#using-ignore-spans). + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + +See `beforeSendSpan` for details. + +### Using + + + +Only available in stream mode. + + + +You can use the option to filter out spans by name: + +```dart +options.ignoreSpans = [ + IgnoreSpanRule.nameEquals('health-check'), + IgnoreSpanRule.nameStartsWith('internal.'), +]; +``` + +See `ignoreSpans` for details. + ### Using -**Note:** The and config options are mutually exclusive. If you define a to filter out certain transactions, you must also handle the case of non-filtered transactions by returning the rate at which you'd like them sampled. +**Note:** The and config options are mutually exclusive. If you define a to filter out certain transactions/service spans, you must also handle the case of non-filtered transactions/service spans by returning the rate at which you'd like them sampled. In its simplest form, used just for filtering the transaction, it looks like this: -It also allows you to sample different transactions at different rates. +It also allows you to sample different transactions/service spans at different rates. -If the transaction currently being processed has a parent transaction (from an upstream service calling this service), the parent (upstream) sampling decision will always be included in the sampling context data, so that your can choose whether and when to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. See Inheriting the parent sampling decision to learn more. +If the transaction or span currently being processed has a parent (from an upstream service calling this service), the parent's (upstream) sampling decision will always be included in the sampling context data, so that your can choose whether and when to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. See Inheriting the parent sampling decision to learn more. -Learn more about configuring the sample rate. +Learn more about configuring sampling. diff --git a/docs/platforms/dart/common/configuration/options.mdx b/docs/platforms/dart/common/configuration/options.mdx index dce0967cce620..fc44bc03de1e9 100644 --- a/docs/platforms/dart/common/configuration/options.mdx +++ b/docs/platforms/dart/common/configuration/options.mdx @@ -198,6 +198,28 @@ By the time is executed, all scope data + + + + +Only available in stream mode. + + + +This function is called with a span event object `SentrySpanV2` and can return a modified span object. Use it to scrub or modify span attributes before the span is sent to Sentry. Unlike other `beforeSend` callbacks, it can't drop spans — use [`ignoreSpans`](#ignoreSpans) for that. + + + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + + + + + This function is called with an SDK-specific breadcrumb object before the breadcrumb is added to the scope. When nothing is returned from the function, the breadcrumb is dropped. To pass the breadcrumb through, return the first argument, which contains the breadcrumb object. @@ -227,6 +249,52 @@ A number between `0` and `1`, controlling the percentage chance a given transact A function responsible for determining the percentage chance a given transaction will be sent to Sentry. It will automatically be passed information about the transaction and the context in which it's being created, and must return a number between `0` (0% chance of being sent) and `1` (100% chance of being sent). Can also be used for filtering transactions, by returning 0 for those that are unwanted. Either this or must be defined to enable tracing. + + +In stream mode, the sampling context is different: read the span's `name` and `attributes` from `samplingContext.spanContext` instead of the transaction context. See Streamed Spans for details. + + + + + + + +Controls how spans are collected and sent to Sentry. + +- In transaction mode (`SentryTraceLifecycle.static`, the default), spans are buffered and sent together as a transaction. +- In stream mode (`SentryTraceLifecycle.stream`), spans are sent to Sentry in batches as they finish. + + + + + + + +Only available in stream mode. + + + +A list of `IgnoreSpanRule`s that drop spans whose name matches a rule (`nameEquals`, `nameStartsWith`, `nameContains`, or `nameEndsWith`). `ignoreSpans` is evaluated at span start, so only the span names available at that point are taken into account. When an ignored span has children, the children are re-parented to the nearest recording ancestor rather than dropped. + +| Factory | Matches | +| ---------------------------------------- | --------------------------------- | +| `IgnoreSpanRule.nameEquals(String)` | Exact span name | +| `IgnoreSpanRule.nameStartsWith(Pattern)` | Name prefix (String or RegExp) | +| `IgnoreSpanRule.nameContains(Pattern)` | Name substring (String or RegExp) | +| `IgnoreSpanRule.nameEndsWith(String)` | Name suffix | + + + +```dart +options.ignoreSpans = [ + IgnoreSpanRule.nameEquals('health-check'), + IgnoreSpanRule.nameStartsWith('internal.'), + IgnoreSpanRule.nameContains('metrics'), + IgnoreSpanRule.nameEndsWith('.bg'), +]; +``` + + diff --git a/docs/platforms/dart/common/configuration/sampling.mdx b/docs/platforms/dart/common/configuration/sampling.mdx index e714c315cfb2b..942933c24fbfc 100644 --- a/docs/platforms/dart/common/configuration/sampling.mdx +++ b/docs/platforms/dart/common/configuration/sampling.mdx @@ -22,29 +22,34 @@ Changing the error sample rate requires re-deployment. In addition, setting an S ## Sampling Transaction Events -We recommend sampling your transactions for two reasons: + + +This page covers both transaction mode (default, using transactions) and stream mode (using service spans). See Streamed Spans to learn more. + + + +We recommend sampling your transactions/service spans for two reasons: 1. Capturing a single trace involves minimal overhead, but capturing traces for _every_ page load or _every_ API request may add an undesirable load to your system. 2. Enabling sampling allows you to better manage the number of events sent to Sentry, so you can tailor your volume to your organization's needs. -Choose a sampling rate with the goal of finding a balance between performance and volume concerns with data accuracy. You don't want to collect _too_ much data, but you want to collect sufficient data from which to draw meaningful conclusions. If you’re not sure what rate to choose, start with a low value and gradually increase it as you learn more about your traffic patterns and volume. +Choose a sampling rate with the goal of finding a balance between performance and volume concerns with data accuracy. You don't want to collect _too_ much data, but you want to collect sufficient data from which to draw meaningful conclusions. If you're not sure what rate to choose, start with a low value and gradually increase it as you learn more about your traffic patterns and volume. -## Configuring the Transaction Sample Rate +## Configuring the Sample Rate -The Sentry SDKs have two configuration options to control the volume of transactions sent to Sentry, allowing you to take a representative sample: +The Sentry SDKs have two configuration options to control the volume of transactions/service spans sent to Sentry, allowing you to take a representative sample: 1. Uniform sample rate (): - - - Provides an even cross-section of transactions, no matter where in your app or under what circumstances they occur. + - Provides an even cross-section of transactions/service spans, no matter where in your app or under what circumstances they occur. - Uses default [inheritance](#inheritance) and [precedence](#precedence) behavior 2. Sampling function () which: - - Samples different transactions at different rates - - Filters out some - transactions entirely + - Samples different transactions/service spans at different rates + - Filters out + some transactions/service spans entirely - Modifies default [precedence](#precedence) and [inheritance](#inheritance) behavior -By default, none of these options are set, meaning no transactions will be sent to Sentry. You must set either one of the options to start sending transactions. +By default, none of these options are set, meaning no transactions/service spans will be sent to Sentry. You must set either one of the options to start sending them. ### Setting a Uniform Sample Rate @@ -58,23 +63,29 @@ By default, none of these options are set, meaning no transactions will be sent ### Default Sampling Context Data -The information contained in the object passed to the when a transaction is created varies by platform and integration. +The information contained in the object passed to the when a transaction/service span is created varies by platform and integration. ### Custom Sampling Context Data -When using custom instrumentation to create a transaction, you can add data to the by passing it as an optional second argument to . This is useful if there's data to which you want the sampler to have access but which you don't want to attach to the transaction as `tags` or `data`, such as information that's sensitive or that’s too large to send with the transaction. For example: + + +This only applies to transaction mode. In stream mode there's no custom sampling context — pass data as span attributes when you start the span, then read them from `samplingContext.spanContext.attributes` in your `tracesSampler`. See [Setting a Sampling Function](#setting-a-sampling-function). + + + +When using custom instrumentation to create a transaction, you can add data to the by passing it as an optional second argument to . This is useful if there's data to which you want the sampler to have access but which you don't want to attach to the transaction as `tags` or `data`, such as information that's sensitive or that's too large to send with the transaction. For example: ## Inheritance -Whatever a transaction's sampling decision, that decision will be passed to its child spans and from there to any transactions they subsequently cause in other services. +Whatever a transaction's/service span's sampling decision, that decision will be passed to its child spans and from there to any transactions they subsequently cause in other services. (See Distributed Tracing for more about how that propagation is done.) -If the transaction currently being created is one of those subsequent transactions (in other words, if it has a parent transaction), the upstream (parent) sampling decision will be included in the sampling context data. Your can use this information to choose whether to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. +If the transaction/service span currently being created is one of those subsequent transactions/service spans (in other words, if it has a parent transaction/service span), the upstream (parent) sampling decision will be included in the sampling context data. Your can use this information to choose whether to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. @@ -86,23 +97,29 @@ If you're using a rather than a ## Forcing a Sampling Decision + + +This only applies to transaction mode. In stream mode you can't force a decision at span creation — control sampling with a `tracesSampler` that reads the span's `name` and `attributes`. + + + If you know at transaction creation time whether or not you want the transaction sent to Sentry, you also have the option of passing a sampling decision directly to the transaction constructor (note, not in the object). If you do that, the transaction won't be subject to the , nor will be run, so you can count on the decision that's passed not to be overwritten. ## Precedence -There are multiple ways for a transaction to end up with a sampling decision. +There are multiple ways for a transaction/service span to end up with a sampling decision. - Random sampling according to a static sample rate set in - Random sampling according to a sample function rate returned by - Absolute decision (100% chance or 0% chance) returned by -- If the transaction has a parent, inheriting its parent's sampling decision +- If the transaction/service span has a parent, inheriting its parent's sampling decision - Absolute decision passed to When there's the potential for more than one of these to come into play, the following precedence rules apply: 1. If a sampling decision is passed to , that decision will be used, overriding everything else. -1. If is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, use the sampling context data to make its own decision, or choose a sample rate for the transaction. We advise against overriding the parent sampling decision because it will break distributed traces) +1. If is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, use the sampling context data to make its own decision, or choose a sample rate for the transaction/service span. We advise against overriding the parent sampling decision because it will break distributed traces) 1. If is not defined, but there's a parent sampling decision, the parent sampling decision will be used. 1. If is not defined and there's no parent sampling decision, will be used. diff --git a/docs/platforms/dart/common/data-management/sensitive-data/index.mdx b/docs/platforms/dart/common/data-management/sensitive-data/index.mdx index 10a3392579264..b145d84990b10 100644 --- a/docs/platforms/dart/common/data-management/sensitive-data/index.mdx +++ b/docs/platforms/dart/common/data-management/sensitive-data/index.mdx @@ -35,9 +35,9 @@ If you _do not_ wish to use the default PII behavior, you can also choose to ide ## Scrubbing Data -### & +### , , & -SDKs provide a hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. Some SDKs also provide a hook which does the same thing for transactions. We recommend using and in the SDKs to **scrub any data before it is sent**, to ensure that sensitive data never leaves the local environment. +The SDK provides a hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. It also provides a hook, that does the same thing for transactions, and a hook, that does the same thing for spans in stream mode. We recommend using these hooks in the SDKs to **scrub any data before it is sent**, to ensure that sensitive data never leaves the local environment. @@ -47,7 +47,7 @@ Sensitive data may appear in the following areas: - Breadcrumbs → Some SDKs (JavaScript and the Java logging integrations, for example) will pick up previously executed log statements. **Do not log PII** if using this feature and including log statements as breadcrumbs in the event. Some backend SDKs will also record database queries, which may need to be scrubbed. Most SDKs will add the HTTP query string and fragment as a data attribute to the breadcrumb, which may need to be scrubbed. - User context → Automated behavior is controlled via . - HTTP context → Query strings may be picked up in some frameworks as part of the HTTP request context. -- Transaction Names → In certain situations, transaction names might contain sensitive data. For example, a browser's pageload transaction might have a raw URL like `/users/1234/details` as its name (where `1234` is a user id, which may be considered PII). In most cases, our SDKs can parameterize URLs and routes successfully, that is, turn `/users/1234/details` into `/users/:userid/details`. However, depending on the framework, your routing configuration, race conditions, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs. +- Transaction/Service Span Names → In certain situations, transaction or span names might contain sensitive data. For example, a browser's pageload transaction/service span might have a raw URL like `/users/1234/details` as its name (where `1234` is a user id, which may be considered PII). In most cases, our SDKs can parameterize URLs and routes successfully, that is, turn `/users/1234/details` into `/users/:userid/details`. However, depending on the framework, your routing configuration, race conditions, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs. - HTTP Spans → Most SDKs will include the HTTP query string and fragment as a data attribute, which means the HTTP span may need to be scrubbed. For more details and data filtering instructions, see Filtering Events. diff --git a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx index 3233e63fc2811..291a7b99700df 100644 --- a/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx +++ b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx @@ -127,7 +127,7 @@ Manual assignment is only needed to override the automatic default. `beforeSendTransaction` has **no effect** in stream mode — transactions are never created, so the callback is never invoked. Migrate its logic to `beforeSendSpan` to modify spans and `ignoreSpans` to drop them: ```dart diff -- options.beforeSendTransaction = (transaction) { +- options.beforeSendTransaction = (transaction, hint) { - // scrub sensitive data, drop transactions by name, etc. - return transaction; - }; @@ -139,7 +139,22 @@ Manual assignment is only needed to override the automatic default. + ]; ``` -Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. `beforeSendSpan` runs when each span ends, so it sees the full set of attributes, including any added during the span's lifetime. `ignoreSpans`, by contrast, is evaluated when a span is created and matches on the span name only. Remove the `beforeSendTransaction` option after migrating its logic. See Extended Configuration for details. +`ignoreTransactions` also has **no effect** in stream mode. Replace it with `ignoreSpans`: + +```dart diff +- options.ignoreTransactions = [ +- 'health-check', +- r'^internal\.', +- ]; ++ options.ignoreSpans = [ ++ IgnoreSpanRule.nameContains('health-check'), ++ IgnoreSpanRule.nameStartsWith('internal.'), ++ ]; +``` + +`ignoreTransactions` interprets each entry as a case-insensitive regular expression and matches substrings by default. `ignoreSpans` uses explicit, case-sensitive rules. Choose `nameContains`, `nameEquals`, `nameStartsWith`, or `nameEndsWith` based on the existing pattern. Pass a `RegExp` to `nameContains` or `nameStartsWith` when needed. + +Note that `beforeSendSpan` is mutation-only and cannot drop spans — use `ignoreSpans` for that. `beforeSendSpan` runs when each span ends, so it sees the full set of attributes, including any added during the span's lifetime. `ignoreSpans`, by contrast, is evaluated when a span is created and matches on the span name only. Remove the `beforeSendTransaction` and `ignoreTransactions` options after migrating their logic. See Extended Configuration for details. ## Sampling diff --git a/docs/platforms/dart/guides/flutter/configuration/filtering.mdx b/docs/platforms/dart/guides/flutter/configuration/filtering.mdx index 2f4e472d0de63..ce9a2b6d9fe4d 100644 --- a/docs/platforms/dart/guides/flutter/configuration/filtering.mdx +++ b/docs/platforms/dart/guides/flutter/configuration/filtering.mdx @@ -36,7 +36,8 @@ When the SDK creates an event or breadcrumb for transmission, that transmission Hints are available in two places: -1. / +1. / + 2. `eventProcessors` Event and breadcrumb `hints` are objects containing various information used to put together an event or a breadcrumb. Typically `hints` hold the original exception so that additional data can be extracted or grouping can be affected. @@ -87,20 +88,85 @@ If used on a platform other than Web, this setting will be ignored. -## Filtering Transaction Events +## Filtering Transactions and Spans -To prevent certain transactions from being reported to Sentry, use the or configuration option, which allows you to provide a function to evaluate the current transaction and drop it if it's not one you want. +Use to make a sampling decision when a transaction or service span starts. Return `0` to drop it. + +In transaction mode, use to drop transactions by name or to modify or drop them with custom logic. In stream mode, use to drop spans by name or to modify them. + +### Using + + + +Not available in stream mode. Use instead. + + + +You can use the option to filter out transactions that match a certain pattern. This option receives a list of string patterns, treats them as case-insensitive regular expressions, and matches them against the transaction name. Patterns match substrings by default. Use `^` and `$` to match the full transaction name. + + + +### Using + + + +Only available in transaction mode. In stream mode, use to modify spans and to drop them. + + + +Use the callback to modify or drop a transaction immediately before it's sent. Return the transaction to send it, or return `null` to drop it. + + ### Using -**Note:** The and config options are mutually exclusive. If you define a to filter out certain transactions, you must also handle the case of non-filtered transactions by returning the rate at which you'd like them sampled. +**Note:** The and config options are mutually exclusive. If you define a to filter out certain transactions/service spans, you must also handle the case of non-filtered transactions/service spans by returning the rate at which you'd like them sampled. -In its simplest form, used just for filtering the transaction, it looks like this: +In its simplest form, used just for filtering the transaction/service span, it looks like this: -It also allows you to sample different transactions at different rates. +It also allows you to sample different transactions/service spans at different rates. + +If the transaction or span currently being processed has a parent (from an upstream service calling this service), the parent's (upstream) sampling decision will always be included in the sampling context data, so that your can choose whether and when to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. See Inheriting the parent sampling decision to learn more. + +Learn more about configuring sampling. + +### Using + + + +Only available in stream mode. + + + +Use the configuration option to modify a span. It runs when each span ends. + +If you want to drop spans, use [](#using-ignore-spans). + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + +See `beforeSendSpan` for details. + +### Using + + + +Only available in stream mode. + + + +You can use the option to filter out spans by name: -If the transaction currently being processed has a parent transaction (from an upstream service calling this service), the parent (upstream) sampling decision will always be included in the sampling context data, so that your can choose whether and when to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. See Inheriting the parent sampling decision to learn more. +```dart +options.ignoreSpans = [ + IgnoreSpanRule.nameEquals('health-check'), + IgnoreSpanRule.nameStartsWith('internal.'), +]; +``` -Learn more about configuring the sample rate. +See `ignoreSpans` for details. diff --git a/docs/platforms/dart/guides/flutter/configuration/options.mdx b/docs/platforms/dart/guides/flutter/configuration/options.mdx index 4143a5a2f7ecd..7195b1771a641 100644 --- a/docs/platforms/dart/guides/flutter/configuration/options.mdx +++ b/docs/platforms/dart/guides/flutter/configuration/options.mdx @@ -225,6 +225,28 @@ By the time is executed, all scope data + + + + +Only available in stream mode. + + + +This function is called with a span event object `SentrySpanV2` and can return a modified span object. Use it to scrub or modify span attributes before the span is sent to Sentry. Unlike other `beforeSend` callbacks, it can't drop spans — use [`ignoreSpans`](#ignoreSpans) for that. + + + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + + + + + This function is called with an SDK-specific breadcrumb object before the breadcrumb is added to the scope. When nothing is returned from the function, the breadcrumb is dropped. To pass the breadcrumb through, return the first argument, which contains the breadcrumb object. @@ -254,6 +276,52 @@ A number between `0` and `1`, controlling the percentage chance a given transact A function responsible for determining the percentage chance a given transaction will be sent to Sentry. It will automatically be passed information about the transaction and the context in which it's being created, and must return a number between `0` (0% chance of being sent) and `1` (100% chance of being sent). Can also be used for filtering transactions, by returning 0 for those that are unwanted. Either this or must be defined to enable tracing. + + +In stream mode, the sampling context is different: read the span's `name` and `attributes` from `samplingContext.spanContext` instead of the transaction context. See Streamed Spans for details. + + + + + + + +Controls how spans are collected and sent to Sentry. + +- In transaction mode (`SentryTraceLifecycle.static`, the default), spans are buffered and sent together as a transaction. +- In stream mode (`SentryTraceLifecycle.stream`), spans are sent to Sentry in batches as they finish. + + + + + + + +Only available in stream mode. + + + +A list of `IgnoreSpanRule`s that drop spans whose name matches a rule (`nameEquals`, `nameStartsWith`, `nameContains`, or `nameEndsWith`). `ignoreSpans` is evaluated at span start, so only the span names available at that point are taken into account. When an ignored span has children, the children are re-parented to the nearest recording ancestor rather than dropped. + +| Factory | Matches | +| ---------------------------------------- | --------------------------------- | +| `IgnoreSpanRule.nameEquals(String)` | Exact span name | +| `IgnoreSpanRule.nameStartsWith(Pattern)` | Name prefix (String or RegExp) | +| `IgnoreSpanRule.nameContains(Pattern)` | Name substring (String or RegExp) | +| `IgnoreSpanRule.nameEndsWith(String)` | Name suffix | + + + +```dart +options.ignoreSpans = [ + IgnoreSpanRule.nameEquals('health-check'), + IgnoreSpanRule.nameStartsWith('internal.'), + IgnoreSpanRule.nameContains('metrics'), + IgnoreSpanRule.nameEndsWith('.bg'), +]; +``` + + diff --git a/docs/platforms/dart/guides/flutter/configuration/sampling.mdx b/docs/platforms/dart/guides/flutter/configuration/sampling.mdx index 9e06bc53fd237..de8eabbd5c3ed 100644 --- a/docs/platforms/dart/guides/flutter/configuration/sampling.mdx +++ b/docs/platforms/dart/guides/flutter/configuration/sampling.mdx @@ -22,29 +22,34 @@ Changing the error sample rate requires re-deployment. In addition, setting an S ## Sampling Transaction Events -We recommend sampling your transactions for two reasons: + + +This page covers both transaction mode (default, using transactions) and stream mode (using service spans). See Streamed Spans to learn more. + + + +We recommend sampling your transactions/service spans for two reasons: 1. Capturing a single trace involves minimal overhead, but capturing traces for _every_ page load or _every_ API request may add an undesirable load to your system. 2. Enabling sampling allows you to better manage the number of events sent to Sentry, so you can tailor your volume to your organization's needs. -Choose a sampling rate with the goal of finding a balance between performance and volume concerns with data accuracy. You don't want to collect _too_ much data, but you want to collect sufficient data from which to draw meaningful conclusions. If you’re not sure what rate to choose, start with a low value and gradually increase it as you learn more about your traffic patterns and volume. +Choose a sampling rate with the goal of finding a balance between performance and volume concerns with data accuracy. You don't want to collect _too_ much data, but you want to collect sufficient data from which to draw meaningful conclusions. If you're not sure what rate to choose, start with a low value and gradually increase it as you learn more about your traffic patterns and volume. -## Configuring the Transaction Sample Rate +## Configuring the Sample Rate -The Sentry SDKs have two configuration options to control the volume of transactions sent to Sentry, allowing you to take a representative sample: +The Sentry SDKs have two configuration options to control the volume of transactions/service spans sent to Sentry, allowing you to take a representative sample: 1. Uniform sample rate (): - - - Provides an even cross-section of transactions, no matter where in your app or under what circumstances they occur. + - Provides an even cross-section of transactions/service spans, no matter where in your app or under what circumstances they occur. - Uses default [inheritance](#inheritance) and [precedence](#precedence) behavior 2. Sampling function () which: - - Samples different transactions at different rates - - Filters out some - transactions entirely + - Samples different transactions/service spans at different rates + - Filters out + some transactions entirely - Modifies default [precedence](#precedence) and [inheritance](#inheritance) behavior -By default, none of these options are set, meaning no transactions will be sent to Sentry. You must set either one of the options to start sending transactions. +By default, none of these options are set, meaning no transactions/service spans will be sent to Sentry. You must set either one of the options to start sending them. ### Setting a Uniform Sample Rate @@ -58,23 +63,29 @@ By default, none of these options are set, meaning no transactions will be sent ### Default Sampling Context Data -The information contained in the object passed to the when a transaction is created varies by platform and integration. +The information contained in the object passed to the when a transaction/service span is created varies by platform and integration. ### Custom Sampling Context Data + + +This only applies to transaction mode. In stream mode there's no custom sampling context — pass data as span attributes when you start the span, then read them from `samplingContext.spanContext.attributes` in your `tracesSampler`. See [Setting a Sampling Function](#setting-a-sampling-function). + + + When using custom instrumentation to create a transaction, you can add data to the by passing it as an optional second argument to . This is useful if there's data to which you want the sampler to have access but which you don't want to attach to the transaction as `tags` or `data`, such as information that's sensitive or that’s too large to send with the transaction. For example: ## Inheritance -Whatever a transaction's sampling decision, that decision will be passed to its child spans and from there to any transactions they subsequently cause in other services. +Whatever a transaction's/service span's sampling decision, that decision will be passed to its child spans and from there to any transactions/service spans they subsequently cause in other services. (See Distributed Tracing for more about how that propagation is done.) -If the transaction currently being created is one of those subsequent transactions (in other words, if it has a parent transaction), the upstream (parent) sampling decision will be included in the sampling context data. Your can use this information to choose whether to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. +If the transaction/service span currently being created is one of those subsequent transactions/service spans (in other words, if it has a parent transaction/service span), the upstream (parent) sampling decision will be included in the sampling context data. Your can use this information to choose whether to inherit that decision. In most cases, inheritance is the right choice, to avoid breaking distributed traces. A broken trace will not include all your services. @@ -86,23 +97,29 @@ If you're using a rather than a ## Forcing a Sampling Decision + + +This only applies to transaction mode. In stream mode you can't force a decision at span creation — control sampling with a `tracesSampler` that reads the span's `name` and `attributes`. + + + If you know at transaction creation time whether or not you want the transaction sent to Sentry, you also have the option of passing a sampling decision directly to the transaction constructor (note, not in the object). If you do that, the transaction won't be subject to the , nor will be run, so you can count on the decision that's passed not to be overwritten. ## Precedence -There are multiple ways for a transaction to end up with a sampling decision. +There are multiple ways for a transaction/service span to end up with a sampling decision. - Random sampling according to a static sample rate set in - Random sampling according to a sample function rate returned by - Absolute decision (100% chance or 0% chance) returned by -- If the transaction has a parent, inheriting its parent's sampling decision +- If the transaction/service span has a parent, inheriting its parent's sampling decision - Absolute decision passed to When there's the potential for more than one of these to come into play, the following precedence rules apply: 1. If a sampling decision is passed to , that decision will be used, overriding everything else. -1. If is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, use the sampling context data to make its own decision, or choose a sample rate for the transaction. We advise against overriding the parent sampling decision because it will break distributed traces) +1. If is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, use the sampling context data to make its own decision, or choose a sample rate for the transaction/service span. We advise against overriding the parent sampling decision because it will break distributed traces) 1. If is not defined, but there's a parent sampling decision, the parent sampling decision will be used. 1. If is not defined and there's no parent sampling decision, will be used. diff --git a/docs/platforms/dart/guides/flutter/data-management/sensitive-data/index.mdx b/docs/platforms/dart/guides/flutter/data-management/sensitive-data/index.mdx index 10a3392579264..f6f1128abcc8c 100644 --- a/docs/platforms/dart/guides/flutter/data-management/sensitive-data/index.mdx +++ b/docs/platforms/dart/guides/flutter/data-management/sensitive-data/index.mdx @@ -35,9 +35,9 @@ If you _do not_ wish to use the default PII behavior, you can also choose to ide ## Scrubbing Data -### & +### , , & -SDKs provide a hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. Some SDKs also provide a hook which does the same thing for transactions. We recommend using and in the SDKs to **scrub any data before it is sent**, to ensure that sensitive data never leaves the local environment. +The SDK provides a hook, which is invoked before an error or message event is sent and can be used to modify event data to remove sensitive information. It also provides a hook, that does the same thing for transactions, and a hook, that does the same thing for spans in stream mode. We recommend using these hooks in the SDKs to **scrub any data before it is sent**, to ensure that sensitive data never leaves the local environment. @@ -47,7 +47,7 @@ Sensitive data may appear in the following areas: - Breadcrumbs → Some SDKs (JavaScript and the Java logging integrations, for example) will pick up previously executed log statements. **Do not log PII** if using this feature and including log statements as breadcrumbs in the event. Some backend SDKs will also record database queries, which may need to be scrubbed. Most SDKs will add the HTTP query string and fragment as a data attribute to the breadcrumb, which may need to be scrubbed. - User context → Automated behavior is controlled via . - HTTP context → Query strings may be picked up in some frameworks as part of the HTTP request context. -- Transaction Names → In certain situations, transaction names might contain sensitive data. For example, a browser's pageload transaction might have a raw URL like `/users/1234/details` as its name (where `1234` is a user id, which may be considered PII). In most cases, our SDKs can parameterize URLs and routes successfully, that is, turn `/users/1234/details` into `/users/:userid/details`. However, depending on the framework, your routing configuration, race conditions, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs. +- Transaction/Service Span Names → In certain situations, transaction and span names might contain sensitive data. For example, a browser's pageload transaction/service span might have a raw URL like `/users/1234/details` as its name (where `1234` is a user id, which may be considered PII). In most cases, our SDKs can parameterize URLs and routes successfully, that is, turn `/users/1234/details` into `/users/:userid/details`. However, depending on the framework, your routing configuration, race conditions, and a few other factors, the SDKs might not be able to completely parameterize all of your URLs. - HTTP Spans → Most SDKs will include the HTTP query string and fragment as a data attribute, which means the HTTP span may need to be scrubbed. For more details and data filtering instructions, see Filtering Events. diff --git a/docs/platforms/dart/guides/flutter/profiling/index.mdx b/docs/platforms/dart/guides/flutter/profiling/index.mdx index c092562d3ec24..16c932371841e 100644 --- a/docs/platforms/dart/guides/flutter/profiling/index.mdx +++ b/docs/platforms/dart/guides/flutter/profiling/index.mdx @@ -21,7 +21,6 @@ Flutter Profiling is currently in Alpha and available only for **iOS** and **mac Profiling depends on Sentry’s Tracing product being enabled beforehand. To enable tracing in the SDK: - ```dart {diff} SentryFlutter.init( (options) => { @@ -39,7 +38,6 @@ Check out the tracing setup documentation { diff --git a/platform-includes/configuration/before-send-transaction/dart.flutter.mdx b/platform-includes/configuration/before-send-transaction/dart.flutter.mdx new file mode 100644 index 0000000000000..f99be96dca907 --- /dev/null +++ b/platform-includes/configuration/before-send-transaction/dart.flutter.mdx @@ -0,0 +1,11 @@ +```dart {2-8} +await SentryFlutter.init((options) { + options.beforeSendTransaction = (transaction, hint) { + if (transaction.transaction == 'health-check') { + return null; + } + + return transaction; + }; +}); +``` diff --git a/platform-includes/configuration/before-send-transaction/dart.mdx b/platform-includes/configuration/before-send-transaction/dart.mdx new file mode 100644 index 0000000000000..772c6e02a6bd5 --- /dev/null +++ b/platform-includes/configuration/before-send-transaction/dart.mdx @@ -0,0 +1,11 @@ +```dart {2-8} +await Sentry.init((options) { + options.beforeSendTransaction = (transaction, hint) { + if (transaction.transaction == 'health-check') { + return null; + } + + return transaction; + }; +}); +``` diff --git a/platform-includes/configuration/ignore-transactions/dart.flutter.mdx b/platform-includes/configuration/ignore-transactions/dart.flutter.mdx new file mode 100644 index 0000000000000..7da19a474114f --- /dev/null +++ b/platform-includes/configuration/ignore-transactions/dart.flutter.mdx @@ -0,0 +1,5 @@ +```dart {2} +await SentryFlutter.init((options) { + options.ignoreTransactions = ['my-transaction', r'^transaction-.*$']; +}); +``` diff --git a/platform-includes/configuration/ignore-transactions/dart.mdx b/platform-includes/configuration/ignore-transactions/dart.mdx index c9367418ce72f..76eed18de877c 100644 --- a/platform-includes/configuration/ignore-transactions/dart.mdx +++ b/platform-includes/configuration/ignore-transactions/dart.mdx @@ -1,5 +1,5 @@ ```dart {2} await Sentry.init((options) { - options.ignoreTransactions = ["my-transaction", "^transaction-.*\$" ]; + options.ignoreTransactions = ['my-transaction', r'^transaction-.*$']; }); ``` diff --git a/platform-includes/performance/sampling-function-intro/dart.flutter.mdx b/platform-includes/performance/sampling-function-intro/dart.flutter.mdx index bd4744dadd4f8..88e01f9394979 100644 --- a/platform-includes/performance/sampling-function-intro/dart.flutter.mdx +++ b/platform-includes/performance/sampling-function-intro/dart.flutter.mdx @@ -1,3 +1,5 @@ -To use the sampling function, set the option in your `SentryFlutter.init()` to a function that will accept a dictionary and return a sample rate between 0 and 1. For example: +To use the sampling function, set the option in your `SentryFlutter.init()` to a function that will accept a dictionary and return a sample rate between 0 and 1. + +In stream mode, receives a different context – read the span's `name` and `attributes` form `samplingContext.spanContext`. diff --git a/platform-includes/performance/sampling-function-intro/dart.mdx b/platform-includes/performance/sampling-function-intro/dart.mdx index b8b6f0787f233..346923fa55004 100644 --- a/platform-includes/performance/sampling-function-intro/dart.mdx +++ b/platform-includes/performance/sampling-function-intro/dart.mdx @@ -1,3 +1,5 @@ -To use the sampling function, set the option in your `Sentry.init()` to a function that will accept a dictionary and return a sample rate between 0 and 1. For example: +To use the sampling function, set the option in your `Sentry.init()` to a function that will accept a dictionary and return a sample rate between 0 and 1. + +In stream mode, receives a different context – read the span's `name` and `attributes` form `samplingContext.spanContext`. diff --git a/platform-includes/performance/traces-sampler-as-sampler/dart.flutter.mdx b/platform-includes/performance/traces-sampler-as-sampler/dart.flutter.mdx index 3473d23fc10af..513ed5cc7dc08 100644 --- a/platform-includes/performance/traces-sampler-as-sampler/dart.flutter.mdx +++ b/platform-includes/performance/traces-sampler-as-sampler/dart.flutter.mdx @@ -1,4 +1,4 @@ -```dart +```dart {tabTitle: Transaction Mode (Default)} await SentryFlutter.init((options) { // Determine traces sample rate based on the sampling context options.tracesSampler = (samplingContext) { @@ -26,3 +26,15 @@ await SentryFlutter.init((options) { }; }); ``` + +```dart {tabTitle: Stream Mode} +await SentryFlutter.init((options) { + options.tracesSampler = (samplingContext) { + final spanContext = samplingContext.spanContext; + if (spanContext.name == 'health-check') { + return 0.0; + } + return 0.2; + }; +}); +``` diff --git a/platform-includes/performance/traces-sampler-as-sampler/dart.mdx b/platform-includes/performance/traces-sampler-as-sampler/dart.mdx index 0cee6321597ec..b03736afdac1b 100644 --- a/platform-includes/performance/traces-sampler-as-sampler/dart.mdx +++ b/platform-includes/performance/traces-sampler-as-sampler/dart.mdx @@ -1,4 +1,4 @@ -```dart +```dart {tabTitle: Transaction Mode (Default)} await Sentry.init((options) { // Determine traces sample rate based on the sampling context options.tracesSampler = (samplingContext) { @@ -26,3 +26,15 @@ await Sentry.init((options) { }; }); ``` + +```dart {tabTitle: Stream Mode} +await Sentry.init((options) { + options.tracesSampler = (samplingContext) { + final spanContext = samplingContext.spanContext; + if (spanContext.name == 'health-check') { + return 0.0; + } + return 0.2; + }; +}); +``` diff --git a/platform-includes/performance/uniform-sample-rate/dart.flutter.mdx b/platform-includes/performance/uniform-sample-rate/dart.flutter.mdx index 94c98d1375c13..4d45876ced37c 100644 --- a/platform-includes/performance/uniform-sample-rate/dart.flutter.mdx +++ b/platform-includes/performance/uniform-sample-rate/dart.flutter.mdx @@ -1,3 +1,3 @@ -To do this, set the option in your `SentryFlutter.init()` to a number between 0 and 1. With this option set, every transaction created will have that percentage chance of being sent to Sentry. (So, for example, if you set to `0.2`, approximately 20% of your transactions will get recorded and sent.) That looks like this: +To do this, set the option in your `SentryFlutter.init()` to a number between 0 and 1. With this option set, every transaction/service span created will have that percentage chance of being sent to Sentry. (So, for example, if you set to `0.2`, approximately 20% of your transactions/service spans will get recorded and sent.) That looks like this: diff --git a/platform-includes/performance/uniform-sample-rate/dart.mdx b/platform-includes/performance/uniform-sample-rate/dart.mdx index 3d580beee6739..b2d9024b11879 100644 --- a/platform-includes/performance/uniform-sample-rate/dart.mdx +++ b/platform-includes/performance/uniform-sample-rate/dart.mdx @@ -1,3 +1,3 @@ -To do this, set the option in your `Sentry.init()` to a number between 0 and 1. With this option set, every transaction created will have that percentage chance of being sent to Sentry. (So, for example, if you set to `0.2`, approximately 20% of your transactions will get recorded and sent.) That looks like this: +To do this, set the option in your `Sentry.init()` to a number between 0 and 1. With this option set, every transaction/service span created will have that percentage chance of being sent to Sentry. (So, for example, if you set to `0.2`, approximately 20% of your transactions/service spans will get recorded and sent.) That looks like this: