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/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 new file mode 100644 index 0000000000000..60cba660a3dfc --- /dev/null +++ b/docs/platforms/dart/common/tracing/streamed-spans/index.mdx @@ -0,0 +1,434 @@ +--- +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 +--- + +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. +- **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: + +``` +Trace +│ +└── Root span [service A] + ├── 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. + + + +## Prerequisites + +You need: + +- Tracing configured in + your app +- Sentry SDK `>=9.23.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. + + + 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) + +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. + + + + +```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 { + await Sentry.startSpan('load cart', (_) => loadCart()); + + await Sentry.startSpan('submit payment', (_) => submitPayment()); +}); +``` + + + + + + +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 local 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. + +#### 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 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( + 'payment', + attributes: {'payment.provider': SentryAttribute.string('stripe')}, +); + +// ...later, from a different entry point +void onPaymentComplete() { + paymentSpan.end(); +} +``` + + + + + +#### Retroactively Set Span Timing + + + + + +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 + + + + + +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 { + 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` | +| `SentryAttribute.stringArray(v)` | `List` | +| `SentryAttribute.intArray(v)` | `List` | +| `SentryAttribute.boolArray(v)` | `List` | +| `SentryAttribute.doubleArray(v)` | `List` | + + + +### Set Span Status + +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 { + if (!await isReachable()) { + span.status = SentrySpanStatusV2.error; + return; + } + await sync(); +}); +``` + +## 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`: + + + + +```dart +options.beforeSendSpan = (span) { + span.removeAttribute('http.request.body'); +}; +``` + + + + + + + +`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 are evaluated at span start and match against the span name. Attribute-based matching is not yet supported. + + + + +```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`, no changes are needed — it works the same way in stream mode. + + + + + +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) { + final spanContext = samplingContext.spanContext; + if (spanContext.name == 'health-check') { + return 0.0; + } + return 0.2; +}; +``` + + + + + +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 + +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 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/streamed-spans/migration-guide.mdx b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx new file mode 100644 index 0000000000000..291a7b99700df --- /dev/null +++ b/docs/platforms/dart/common/tracing/streamed-spans/migration-guide.mdx @@ -0,0 +1,174 @@ +--- +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 Streamed Spans. + +## Enable Stream Mode + +Set `traceLifecycle` to `SentryTraceLifecycle.stream` when initializing the SDK: + + + +## Span Creation + +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 { +- await runCheckout(); +- } finally { +- await transaction.finish(); +- } ++ await Sentry.startSpan('checkout', (span) async { ++ span.setAttribute('sentry.op', SentryAttribute.string('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', SentryAttribute.string('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(); ++ } +``` + + + +`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 + +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.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. + +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 + +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, hint) { +- // scrub sensitive data, drop transactions by name, etc. +- return transaction; +- }; ++ options.beforeSendSpan = (span) { ++ span.removeAttribute('http.request.body'); ++ }; ++ options.ignoreSpans = [ ++ IgnoreSpanRule.nameEquals('health-check'), ++ ]; +``` + +`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 + +`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. 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/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/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/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/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/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. + + 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/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(); +}); +``` 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/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; + }); +} +``` 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: