From d888f03aa1a31e54da4a7cb50e44d22f2fe9221a Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Wed, 25 Feb 2026 00:13:03 +0100 Subject: [PATCH] docs(sdk): extract context propagation into foundations spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate distributed tracing, DSC, TwP, trace propagation cheat sheet, and span trace propagation into a single foundations/context-propagation spec. This reduces the traces/ migration surface and places propagation where it conceptually belongs — as a foundational concern, not a tracing detail. - Create context-propagation/index.mdx (v1.9.0) and dynamic-sampling-context.mdx (v1.3.0) sub-spec - Replace extracted sections in traces/index.mdx with cross-references - Delete 5 fully extracted source files - Add redirects for old paths - Update all internal links across 11 files - Unify SpecSection heading placement (always inside component) - Update SpecSection component to visually render heading above the colored border strip while keeping it inside the component for parsing Co-Authored-By: Claude --- .../dynamic-sampling/fidelity-and-biases.mdx | 2 +- .../client/integrations/http-client.mdx | 6 +- .../foundations/state-management/index.mdx | 2 +- .../state-management/scopes/index.mdx | 2 +- .../dynamic-sampling-context.mdx | 177 ++++--- .../foundations/trace-propagation/index.mdx | 488 ++++++++++++++++++ .../transport/event-payloads/contexts.mdx | 2 +- .../standards/api-architecture.mdx | 24 +- .../standards/code-quality.mdx | 28 +- .../standards/code-submission.mdx | 28 +- .../standards/coordination-maintenance.mdx | 20 +- .../standards/release-versioning.mdx | 24 +- .../standards/repository-docs.mdx | 20 +- .../getting-started/standards/review-ci.mdx | 20 +- .../native-sdks/tracing.mdx | 2 +- develop-docs/sdk/telemetry/attachments.mdx | 46 +- develop-docs/sdk/telemetry/check-ins.mdx | 44 +- develop-docs/sdk/telemetry/client-reports.mdx | 20 +- develop-docs/sdk/telemetry/feedbacks.mdx | 36 +- develop-docs/sdk/telemetry/logs.mdx | 84 +-- develop-docs/sdk/telemetry/metrics.mdx | 60 +-- develop-docs/sdk/telemetry/profiles/index.mdx | 64 +-- develop-docs/sdk/telemetry/replays.mdx | 52 +- develop-docs/sdk/telemetry/sessions/index.mdx | 57 +- .../sdk/telemetry/spans/span-buffer.mdx | 2 +- .../spans/span-trace-propagation.mdx | 77 --- .../traces/distributed-tracing/index.mdx | 29 -- develop-docs/sdk/telemetry/traces/index.mdx | 139 +---- .../traces/trace-propagation-cheat-sheet.mdx | 45 -- .../traces/tracing-without-performance.mdx | 135 ----- develop-docs/sdk/telemetry/user-reports.mdx | 8 +- redirects.js | 64 ++- src/components/specSection.tsx | 31 +- 33 files changed, 1006 insertions(+), 832 deletions(-) rename develop-docs/sdk/{telemetry/traces => foundations/trace-propagation}/dynamic-sampling-context.mdx (65%) create mode 100644 develop-docs/sdk/foundations/trace-propagation/index.mdx delete mode 100644 develop-docs/sdk/telemetry/spans/span-trace-propagation.mdx delete mode 100644 develop-docs/sdk/telemetry/traces/distributed-tracing/index.mdx delete mode 100644 develop-docs/sdk/telemetry/traces/trace-propagation-cheat-sheet.mdx delete mode 100644 develop-docs/sdk/telemetry/traces/tracing-without-performance.mdx diff --git a/develop-docs/application-architecture/dynamic-sampling/fidelity-and-biases.mdx b/develop-docs/application-architecture/dynamic-sampling/fidelity-and-biases.mdx index 2a503779caae6..2a3b5f8e5e9a8 100644 --- a/develop-docs/application-architecture/dynamic-sampling/fidelity-and-biases.mdx +++ b/develop-docs/application-architecture/dynamic-sampling/fidelity-and-biases.mdx @@ -56,7 +56,7 @@ A trace is a **collection of events that are related to each other**. For exampl Trace sampling ensures that **either all events of a trace are sampled, or none**. That is, these rules **always yield the same sampling decision** for every event in the same trace. This requires the cooperation of SDKs and thus allows sampling only by `project`, `release`, `environment`, and `transaction` name. -To achieve trace sampling, SDKs pass all fields that can be sampled by [Dynamic Sampling Context (DSC)](/sdk/performance/dynamic-sampling-context/) (defined [here](https://getsentry.github.io/relay/relay_sampling/dsc/struct.DynamicSamplingContext.html)) as they propagate traces. _This ensures that every event from the same trace comes with the same DSC._ +To achieve trace sampling, SDKs pass all fields that can be sampled by [Dynamic Sampling Context (DSC)](/sdk/foundations/trace-propagation/dynamic-sampling-context/) (defined [here](https://getsentry.github.io/relay/relay_sampling/dsc/struct.DynamicSamplingContext.html)) as they propagate traces. _This ensures that every event from the same trace comes with the same DSC._ ![Trace Sampling](./images/traceSampling.png) diff --git a/develop-docs/sdk/foundations/client/integrations/http-client.mdx b/develop-docs/sdk/foundations/client/integrations/http-client.mdx index 9733e0baec052..66b6dbf4a0daa 100644 --- a/develop-docs/sdk/foundations/client/integrations/http-client.mdx +++ b/develop-docs/sdk/foundations/client/integrations/http-client.mdx @@ -59,8 +59,8 @@ If Performance Monitoring is both supported by the SDK and enabled in the client - operation: `http.client` - description: `$METHOD $url` (uppercase HTTP method), e.g. `GET https://sentry.io` -- HTTP requests must be enhanced with a [`sentry-trace` HTTP header](/sdk/telemetry/traces/#header-sentry-trace) to support [distributed tracing](https://docs.sentry.io/product/sentry-basics/tracing/distributed-tracing) -- HTTP requests must be enhanced with a [`baggage` HTTP header](/sdk/telemetry/traces/dynamic-sampling-context/#baggage-header) to support [dynamic sampling](/sdk/telemetry/traces/dynamic-sampling-context/) +- HTTP requests must be enhanced with a [`sentry-trace` HTTP header](/sdk/foundations/trace-propagation/#sentry-trace-header) to support [distributed tracing](https://docs.sentry.io/product/sentry-basics/tracing/distributed-tracing) +- HTTP requests must be enhanced with a [`baggage` HTTP header](/sdk/foundations/trace-propagation/dynamic-sampling-context/#baggage-header) to support [dynamic sampling](/sdk/foundations/trace-propagation/dynamic-sampling-context/) - span status must match HTTP response status code ([see Span status to HTTP status code mapping](/sdk/foundations/transport/event-payloads/span/)) - when network error occurs, span status must be set to `internal_error` - span data must follow the [Span Data Conventions](/sdk/telemetry/traces/span-data-conventions/) @@ -80,7 +80,7 @@ The HTTP Client integration should have 3 configuration options: - `failedRequestStatusCodes` defaults to `500 - 599`, this configuration option accepts a `List` of `HttpStatusCodeRange` which is a range of HTTP status code -> `min` to `max` or a single `status_code`. - The SDK will only capture HTTP Client errors if the HTTP Response status code is within the defined ranges in `failedRequestStatusCodes`. - If the language has a `Range` type, it should be used instead of `HttpStatusCodeRange`. -- `failedRequestTargets` defaults to (`.*`), this configuration option accepts a `List` of `String` that may be Regular expressions as well, similar to tracePropagationTargets. +- `failedRequestTargets` defaults to (`.*`), this configuration option accepts a `List` of `String` that may be Regular expressions as well, similar to tracePropagationTargets. - The SDK will only capture HTTP Client errors if the HTTP Request URL is a match for any of the `failedRequestsTargets`. - While the keys of sensitive HTTP headers (e.g. `Authorization` and `Cookie`) are included, their values must be replaced with `"[Filtered]"` (also see Data Handling: Sensitive Data). diff --git a/develop-docs/sdk/foundations/state-management/index.mdx b/develop-docs/sdk/foundations/state-management/index.mdx index f1abedea83cac..e9691c16a814a 100644 --- a/develop-docs/sdk/foundations/state-management/index.mdx +++ b/develop-docs/sdk/foundations/state-management/index.mdx @@ -1,7 +1,7 @@ --- title: State Management description: How SDKs manage contextual state — scopes, attributes, breadcrumbs, and the deprecated Hub model. -sidebar_order: 4 +sidebar_order: 3 --- diff --git a/develop-docs/sdk/foundations/state-management/scopes/index.mdx b/develop-docs/sdk/foundations/state-management/scopes/index.mdx index 8c0ae043525f8..17ad934b5574f 100644 --- a/develop-docs/sdk/foundations/state-management/scopes/index.mdx +++ b/develop-docs/sdk/foundations/state-management/scopes/index.mdx @@ -278,7 +278,7 @@ The propagation context (trace ID, span ID, baggage/DSC) **MUST** be stored on t - Generating `sentry-trace` and `baggage` headers for outgoing requests - Connecting error events to the active trace (tracing without performance) -The isolation scope is the canonical location for the propagation context. When no active span exists, the propagation context from the isolation scope **MUST** be used. See [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance/) for details. +The isolation scope is the canonical location for the propagation context. When no active span exists, the propagation context from the isolation scope **MUST** be used. See [Trace Propagation: Default Propagation](/sdk/foundations/trace-propagation/#default-propagation) for details. diff --git a/develop-docs/sdk/telemetry/traces/dynamic-sampling-context.mdx b/develop-docs/sdk/foundations/trace-propagation/dynamic-sampling-context.mdx similarity index 65% rename from develop-docs/sdk/telemetry/traces/dynamic-sampling-context.mdx rename to develop-docs/sdk/foundations/trace-propagation/dynamic-sampling-context.mdx index e4d9c4f1d40a2..afb7a96532dea 100644 --- a/develop-docs/sdk/telemetry/traces/dynamic-sampling-context.mdx +++ b/develop-docs/sdk/foundations/trace-propagation/dynamic-sampling-context.mdx @@ -1,8 +1,37 @@ --- title: Dynamic Sampling Context (DSC) +description: How SDKs propagate Dynamic Sampling Context via baggage headers and envelope headers. +spec_id: sdk/foundations/trace-propagation/dynamic-sampling-context +spec_version: 1.3.0 +spec_status: stable +spec_depends_on: + - id: sdk/foundations/trace-propagation + version: ">=1.0.0" + - id: sdk/foundations/transport/envelopes + version: ">=1.0.0" +spec_changelog: + - version: 1.3.0 + date: 2026-02-24 + summary: Moved to trace-propagation sub-spec + - version: 1.2.0 + date: 2025-05-15 + summary: Renamed org to org_id, cleanup + - version: 1.1.0 + date: 2024-11-28 + summary: Added sample_rand and sample_rate fields + - version: 1.0.0 + date: 2022-06-24 + summary: Initial DSC spec +sidebar_order: 1 --- -All data sent to Sentry will end up in a [Trace](https://docs.sentry.io/concepts/key-terms/tracing/distributed-tracing/#traces-transactions-and-spans). Traces can be sampled by the `tracesSampleRate` or `tracesSampler` options in the SDKs. + + + + +## Overview + +All data sent to Sentry will end up in a [Trace](https://docs.sentry.io/concepts/key-terms/tracing/distributed-tracing/#traces-transactions-and-spans). Traces can be sampled by the [`tracesSampleRate`](/sdk/telemetry/traces/#tracessamplerate) or [`tracesSampler`](/sdk/telemetry/traces/#tracessampler) options in the SDKs. Changing those options has quite a few consequences for users of Sentry SDKs: @@ -13,9 +42,9 @@ Changing those options has quite a few consequences for users of Sentry SDKs: The solution for this is **Dynamic Sampling**. Dynamic Sampling allows Sentry to automatically adjust the amount of data retained based on the value of the data. For detailed information see [Dynamic Sampling](/dynamic-sampling/). -## High-Level Problem Statement +### High-Level Problem Statement -### Ingest +#### Ingest Implementing Dynamic Sampling comes with challenges, especially on the ingestion side of things. For Dynamic Sampling, we want to make sampling decisions for entire traces. @@ -30,9 +59,9 @@ As a mental model: The head transaction in a trace determines the Dynamic Sampling Context for all following transactions in that trace. No information can be changed, added or deleted after the first propagation. Dynamic Sampling Context is bound to only one particular trace, and all the transactions that are part of this trace. -Multiple different traces can and should have different Dynamic Sampling Contexts. +Multiple different traces can and **SHOULD** have different Dynamic Sampling Contexts. -### SDKs +#### SDKs SDKs are responsible for propagating a **"Dynamic Sampling Context"** or **"DSC"** across all applications that are part of a trace. This involves: @@ -42,54 +71,59 @@ This involves: 3. Propagating DSC to downstream SDKs (via the `baggage` header). 4. Sending the DSC to Sentry (via the `trace` envelope header). -To align DSC propagation over all our SDKs, we defined a [unified propagation mechanism](#unified-propagation-mechanism) (step-by-step instructions) that all SDK implementations should be able to follow. +To align DSC propagation over all our SDKs, we defined a [unified propagation mechanism](#unified-propagation-mechanism) (step-by-step instructions) that all SDK implementations **SHOULD** be able to follow. + +--- -## DSC Specification +## Behavior -All of the attributes in the table below are required (non-optional) in a sense, that when they are known to an SDK at the time an envelope with an event (transaction or error) is sent to Sentry, or at the time a baggage header is propagated, they must also be included in said envelope or baggage. + + +### DSC Specification + +All of the attributes in the table below are required (non-optional) in a sense, that when they are known to an SDK at the time an envelope with an event (transaction or error) is sent to Sentry, or at the time a baggage header is propagated, they **MUST** also be included in said envelope or baggage. At the moment, only `release`, `environment` and `transaction` are used by the product for dynamic sampling functionality. The rest of the context attributes, `trace_id`, `public_key`, `sampled` and `sample_rate`, are used by Relay for internal decisions and for extrapolation in the product. Additional entries such as `replay_id`, `org_id` and `sample_rand` are only using the DSC as a means of transport. -| Attribute | Type | Description | Example | Required Level | -| --------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ------------------------------------ | -| `trace_id` | string | The original trace ID as generated by the SDK. This must match the trace id of the submitted transaction item. [1] | `771a43a4192642f0b136d5159a501700` | strictly required [0] | -| `public_key` | string | Public key from the DSN used by the SDK. [2] | `49d0f7386ad645858ae85020e393bef3` | strictly required [0] | -| `sample_rate` | string | The sample rate as defined by the user on the SDK. [3] [4] | `0.7` | strictly required [0] | -| `sample_rand` | string | A random number generated at the start of a trace by the head of trace SDK. [4] | `0.5` | required | -| `sampled` | string | `"true"` if the trace is sampled, `"false"` otherwise. This is set by the head of the trace SDK. [4] | `true` | required | -| `release` | string | The release name as specified in client options. | `myapp@1.2.3`, `1.2.3`, `2025.4.107` | required | -| `environment` | string | The environment name as specified in client options. | `production`, `staging` | required | -| `transaction` | string | The transaction name set on the scope. **Only include** if name has [good quality](#note-on-good-quality-transaction-names). | `/login`, `myApp.myController.login` | required (if known and good quality) | -| `org_id` | string | The org ID parsed from the DSN or received by a downstream SDK. | `1` | required | -| `user_segment` [DEPRECATED] | string | User segment as set by the user with `scope.set_user()`. | | deprecated | - -0: In any case, `trace_id`, `public_key`, and `sample_rate` should always be known to an SDK, so these values are strictly required. +| Attribute | Type | Description | Example | Required Level | Since | +| --- | --- | --- | --- | --- | --- | +| `trace_id` | string | The original trace ID as generated by the SDK. This **MUST** match the trace id of the submitted transaction item. [1] | `771a43a4192642f0b136d5159a501700` | strictly required [0] | 1.0.0 | +| `public_key` | string | Public key from the DSN used by the SDK. [2] | `49d0f7386ad645858ae85020e393bef3` | strictly required [0] | 1.0.0 | +| `sample_rate` | string | The sample rate as defined by the user on the SDK. [3] [4] | `0.7` | strictly required [0] | 1.0.0 | +| `sample_rand` | string | A random number generated at the start of a trace by the head of trace SDK. [4] | `0.5` | required | 1.1.0 | +| `sampled` | string | `"true"` if the trace is sampled, `"false"` otherwise. This is set by the head of the trace SDK. [4] | `true` | required | 1.0.0 | +| `release` | string | The release name as specified in client options. | `myapp@1.2.3`, `1.2.3`, `2025.4.107` | required | 1.0.0 | +| `environment` | string | The environment name as specified in client options. | `production`, `staging` | required | 1.0.0 | +| `transaction` | string | The transaction name set on the scope. **Only include** if name has [good quality](#note-on-good-quality-transaction-names). | `/login`, `myApp.myController.login` | required (if known and good quality) | 1.0.0 | +| `org_id` | string | The org ID parsed from the DSN or received by a downstream SDK. | `1` | required | 1.2.0 | +| `user_segment` [DEPRECATED] | string | User segment as set by the user with `scope.set_user()`. | | deprecated | 1.0.0 | + +0: In any case, `trace_id`, `public_key`, and `sample_rate` **SHOULD** always be known to an SDK, so these values are strictly required. 1: UUID V4 encoded as a hexadecimal sequence with no dashes that is a sequence of 32 hexadecimal digits. 2: It allows Sentry to sample traces spanning multiple projects, by resolving the same set of rules based on the starting project. -3: This string should always be a number between (and including) 0 and 1 in a notation that is supported by the [JSON specification](https://www.json.org/json-en.html). If a `tracesSampler` callback was used for the sampling decision, its result should be used for `sample_rate` instead of the `tracesSampleRate` from `SentryOptions`. In case `tracesSampler` returns `True` it should be sent as `1.0`, `False` should be sent as `0.0`. +3: This string **MUST** always be a number between (and including) 0 and 1 in a notation that is supported by the [JSON specification](https://www.json.org/json-en.html). If a `tracesSampler` callback was used for the sampling decision, its result **SHOULD** be used for `sample_rate` instead of the `tracesSampleRate` from `SentryOptions`. In case `tracesSampler` returns `True` it **SHOULD** be sent as `1.0`, `False` **SHOULD** be sent as `0.0`. -4: These attributes must conform to the invariant `sample_rand < sample_rate <=> sampled`. +4: These attributes **MUST** conform to the invariant `sample_rand < sample_rate <=> sampled`. -### Note on good-quality transaction names +#### Note on good-quality transaction names -UX wise for the Dynamic Sampling product, we depend on transaction names (i.e. the `transaction` attribute of the DSC) to have good quality. -Good quality transaction names are descriptive, have proper grouping on Sentry, have low cardinality, and do not contain PII or other identifiers. +UX wise for the Dynamic Sampling product, we depend on transaction names (i.e. the `transaction` attribute of the DSC) to have good quality. Good quality transaction names are descriptive, have proper grouping on Sentry, have low cardinality, and do not contain PII or other identifiers. -For that reason: **Only if a transaction name has good quality, it should be included in the DSC. Otherwise, it cannot be included!** +For that reason: **Only if a transaction name has good quality, it SHOULD be included in the DSC. Otherwise, it MUST NOT be included!** -❌ Examples for **low quality** transaction names: +Examples for **low quality** transaction names: - `"/organization/601242c3-8f49-4158-aef4-c9e42cb1422c/user/601242c3-8f49-4158-aef4-c9e42cb1422c"` - `"UIComponentWithHash_7sd8x823f48_x7b26"` -✅ Examples for **good quality** transaction names: +Examples for **good quality** transaction names: - `"/organization/:organizationId/user/:userId"` - `"UserListUIComponent"` @@ -98,30 +132,22 @@ SDKs can leverage ### Baggage Header -We chose `baggage` as the propagation mechanism for DSC. ([w3c baggage spec](https://www.w3.org/TR/baggage/)). +We chose `baggage` as the propagation mechanism for DSC ([w3c baggage spec](https://www.w3.org/TR/baggage/)). Baggage is a standard HTTP header with URI encoded key-value pairs. For the propagation of DSC, SDKs first read the DSC from the `baggage` header of incoming requests/messages. To propagate DSC to downstream SDKs/services, we create a `baggage` header (or modify an existing one) through HTTP request instrumentation. -The `baggage` header should only be attached to an outgoing request if the request's URL matches at least one entry of the [`tracePropagationTargets`](/sdk/performance/#tracepropagationtargets) SDK option or this option is set to `null` or not set. +The `baggage` header **MUST** only be attached to an outgoing request if the request's URL matches at least one entry of the [`tracePropagationTargets`](/sdk/foundations/trace-propagation/#trace-propagation-targets) option or this option is set to `null` or not set. -SDKs must set all of the keys in the form of "`sentry-[name]`". Where `[name]` is the attribute in the [DSC Specification](#dsc-specification). The prefix "`sentry-`" acts to identify key-value pairs set by Sentry SDKs. +SDKs **MUST** set all of the keys in the form of "`sentry-[name]`". Where `[name]` is the attribute in the [DSC Specification](#dsc-specification). The prefix "`sentry-`" acts to identify key-value pairs set by Sentry SDKs. The following is an example of what a baggage header containing Dynamic Sampling Context might look like: @@ -132,52 +158,66 @@ baggage: other-vendor-value-1=foo;bar;baz, sentry-trace_id=771a43a4192642f0b136d The `sentry-` prefix allows SDKs to put all of the sentry key-value pairs from the `baggage` directly onto the envelope header, after stripping away the `sentry-` prefix. Being able to simply copy key-value pairs from the `baggage` header onto the `trace` envelope header gives us the flexibility to provide dedicated API methods to propagate additional values using Dynamic Sampling Context. -This, in return, allows users to define their own values in the Dynamic Sampling Context so they can sample by those in the Sentry interface. #### Note on `baggage` headers from other vendors Other vendors might also be using the `baggage` header. -If a `baggage` header already exists on an outgoing request, SDKs should aim to be good citizens by only **appending** Sentry values to the header. +If a `baggage` header already exists on an outgoing request, SDKs **SHOULD** be good citizens by only **appending** Sentry values to the header. In cases where we cannot access the outgoing request's headers, it is fine to add a separate sentry-only `baggage` header and rely on downstream servers to stitch them together eventually ([RFC 2616](https://www.rfc-editor.org/rfc/rfc2616#section-4.2)). -In the case that another vendor added Sentry values to an outgoing request, SDKs may overwrite those values. +In the case that another vendor added Sentry values to an outgoing request, SDKs **MAY** overwrite those values. -SDKs must not add other vendors' baggage from incoming requests to outgoing requests. +SDKs **MUST NOT** add other vendors' baggage from incoming requests to outgoing requests. Sentry SDKs only concern themselves with Sentry baggage. On the Java SDK ([1](https://github.com/getsentry/sentry-java/blob/725a1edc2b1c713f4d91fef6985e9c98ef2bd873/sentry/src/main/java/io/sentry/Span.java#L149-L150) [2](https://github.com/getsentry/sentry-java/blob/725a1edc2b1c713f4d91fef6985e9c98ef2bd873/sentry/src/main/java/io/sentry/BaggageHeader.java#L15-L26)) we went with an explicit param for passing in pre-existing headers on the outgoing request (`span.toBaggageHeader(preExistingBaggageHeaders)`) as these are required to produce a new header that respects the limits and only contains Sentry values once. An alternative is to have some util function that does the merging (as done e.g. in the [Dart SDK](https://github.com/getsentry/sentry-dart/blob/c2653112519fb98ceecaf3eeb8106c5ecf38fe40/dart/lib/src/utils/tracing_utils.dart#L9-L41)). -### Freezing Dynamic Sampling Context + + + + +### Envelope Header + +Dynamic Sampling Context is transferred to Sentry through the `trace` envelope header. +The value of this envelope header is a JSON object containing the fields specified in the [DSC Specification](#dsc-specification). + + -As mentioned above, in order to be able to make sampling decisions for entire traces, Dynamic Sampling Context must be the same across all transactions of a trace. + -**What does this mean for SDKs?** +### Freezing DSC + +In order to be able to make sampling decisions for entire traces, Dynamic Sampling Context **MUST** be the same across all transactions of a trace. When starting a new trace, SDKs are no longer allowed to alter the DSC for that trace as soon as this DSC leaves the boundaries of the SDK for the first time. The DSC is then considered "frozen". DSC leaves SDKs in two situations: - When an outgoing request with a `baggage` header, containing the DSC, is made. -- When a transaction envelope containing the DSC is sent to Sentry +- When a transaction envelope containing the DSC is sent to Sentry. -When an SDK receives an HTTP request that was "instrumented" or "traced" by a Sentry SDK, the receiving SDK should consider the incoming DSC as instantly frozen. -Any values on the DSC should be propagated "as is" - this includes values like "environment" or "release". +When an SDK receives an HTTP request that was "instrumented" or "traced" by a Sentry SDK, the receiving SDK **MUST** consider the incoming DSC as instantly frozen. +Any values on the DSC **MUST** be propagated "as is" — this includes values like "environment" or "release". -SDKs should recognize incoming requests as "instrumented" or "traced" when at least one of the following applies: +SDKs **SHOULD** recognize incoming requests as "instrumented" or "traced" when at least one of the following applies: - The incoming request has a `sentry-trace` header - The incoming request has a `sentry-trace` header and `baggage` header containing one or more keys starting with "`sentry-`" -After the DSC of a particular trace has been frozen, API calls like `set_user` should have no effect on the DSC. +After the DSC of a particular trace has been frozen, API calls like `set_user` **MUST** have no effect on the DSC. + + + + ### Unified Propagation Mechanism -SDKs should follow these steps for any incoming and outgoing requests (in python pseudo-code for illustrative purposes): +SDKs **SHOULD** follow these steps for any incoming and outgoing requests (in python pseudo-code for illustrative purposes): ```python def collect_dynamic_sampling_context(): @@ -218,7 +258,11 @@ def on_outgoing_request(request): While there is no strict necessity for the `current_transaction.dynamic_sampling_context_frozen` flag yet, there is a future use case where we need it: We might want users to be able to set Dynamic Sampling Context values themselves. The flag becomes relevant after the first propagation, where Dynamic Sampling Context becomes immutable. -When users attempt to set DSC afterwards, our SDKs should make this operation a noop. +When users attempt to set DSC afterwards, our SDKs **SHOULD** make this operation a noop. + + + +--- ## Considerations and Challenges @@ -227,7 +271,7 @@ These are not blockers to the adoption of the spec, but instead are here as cont ### The Temporal Problem -Unlike `environment` or `release`, which should always be known to an SDK at initialization time, `user_segment`, and `transaction` (name) are only known after SDK initialization time. +Unlike `environment` or `release`, which **SHOULD** always be known to an SDK at initialization time, `user_segment`, and `transaction` (name) are only known after SDK initialization time. This means that if a trace is propagated from a running transaction _BEFORE_ the user/transaction attributes are set, you'll get a portion of transactions in a trace that have different Dynamic Sampling Context than other portions, leading to _dynamic sampling across a trace_ not working as expected for users. Let's say we want to dynamically sample a browser application based on the `user_segment`. @@ -254,16 +298,6 @@ For `transaction` name, the problem is similar, but it is because of parameteriz As much as we can, the SDKs will try to parameterize transaction names (for ex, turn `/teams/123/user/456` into `/teams/:id/user/:id`) so that similar transactions are grouped together in the UI. This improves both aggregate statistics for transactions and the general UX of using the product (setting alerts, checking measurements like web vitals, etc.). For some frameworks, for example React Router v4 - v6, we parameterize the transaction name after the transaction has been started due to constraints with the framework itself. -To illustrate this, let's look at another example: - -- Page starts loading -- Sentry initializes and starts `pageload` transaction (with transaction name `/teams/123/user/456` - based on window URL) -- Page makes HTTP request to service A (propagates sentry-trace/baggage to user service) -- Page renders with react router, triggering parameterization of transaction name (`/teams/123/user/456` -> `/teams/:id/user/:id`). -- Page finishes loading, finishing `pageload` transaction, which is sent to Sentry - -When the `pageload` transaction shows up in Sentry, it'll be called `/teams/:id/user/:id`, but the Dynamic Sampling Context has `/teams/123/user/456` propagated, which means that the transaction from service A will not be affected by any trace-wide dynamic sampling rules put on the transaction name. -This will be very confusing to users, as effectively the transaction name they thinking that works will not. ### Choosing Baggage as the Propagation Mechanism @@ -272,4 +306,9 @@ For more information on this, check the [DACI around using baggage](https://www. Previously, we were using the [w3c Trace Context spec](https://www.w3.org/TR/trace-context/) as the mechanism to propagate dynamic sampling context between SDKs. We switched to the [w3c Baggage spec](https://www.w3.org/TR/baggage) though because it was easier to use, required less code on the SDK side, and had much more [liberal size limits](https://www.w3.org/TR/baggage/#limits) than the trace context spec. To make sure that we were not colliding with user defined keys as baggage is an open standard, we decided to prefix all sentry related keys with `sentry-` as a namespace. -This allowed us to use baggage as an open standard while only having to worry about Sentry data. + +--- + +## Changelog + + diff --git a/develop-docs/sdk/foundations/trace-propagation/index.mdx b/develop-docs/sdk/foundations/trace-propagation/index.mdx new file mode 100644 index 0000000000000..06c6ba49cac4d --- /dev/null +++ b/develop-docs/sdk/foundations/trace-propagation/index.mdx @@ -0,0 +1,488 @@ +--- +title: Trace Propagation +description: How SDKs propagate trace context between services via headers, metadata, and environment variables. +spec_id: sdk/foundations/trace-propagation +spec_version: 1.9.0 +spec_status: stable +spec_depends_on: + - id: sdk/foundations/transport/envelopes + version: ">=1.0.0" + - id: sdk/foundations/state-management/scopes + version: ">=1.0.0" +spec_changelog: + - version: 1.9.0 + date: 2026-02-24 + summary: Consolidated into foundations/trace-propagation + - version: 1.8.0 + date: 2026-01-22 + summary: Added startNewTrace API + - version: 1.7.0 + date: 2025-09-09 + summary: Added propagateTraceparent option + - version: 1.6.0 + date: 2025-08-14 + summary: Re-added W3C traceparent documentation + - version: 1.5.0 + date: 2024-11-06 + summary: Added default propagation behavior without tracing (TwP), deferred sampling + - version: 1.4.0 + date: 2025-04-09 + summary: Added propagation decision matrix + - version: 1.3.0 + date: 2024-11-28 + summary: Added strictTraceContinuation, sample_rand propagation + - version: 1.2.0 + date: 2024-04-09 + summary: Added W3C traceparent header support + - version: 1.1.0 + date: 2023-11-06 + summary: Distributed tracing (carriers, mechanisms, env vars) + - version: 1.0.0 + date: 2022-07-21 + summary: Initial — tracePropagationTargets, sentry-trace header +sidebar_order: 4 +--- + + + + + +## Overview + +SDKs **MUST** propagate trace information between services so that all telemetry (errors, profiles, replays, transactions, check-ins, etc.) from those services can be connected into one trace. + +Trace propagation operates independently of span collection. Even when an SDK is not configured to send spans (i.e. no `tracesSampleRate` or `tracesSampler`), it **MUST** still continue incoming traces, propagate trace data on outgoing requests, and attach trace context to events. This default behavior is sometimes referred to as "Tracing without Performance" (TwP). + +Related specs: +- [Dynamic Sampling Context](/sdk/foundations/trace-propagation/dynamic-sampling-context/) — DSC fields, baggage format, freezing rules +- [Traces](/sdk/telemetry/traces/) — span collection, sampling, transaction payloads +- [Scopes](/sdk/foundations/state-management/scopes/) — propagation context storage + +--- + +## Concepts + +- **Trace context**: The combination of `trace_id`, `span_id`, and sampling decision that identifies a position within a distributed trace. + +- **Propagation context**: The storage location for trace context on the current [scope](/sdk/foundations/state-management/scopes/). The propagation context **SHOULD** be populated with a random `traceId` and `spanId` if no incoming trace is present. + +- **Carriers**: The mechanisms used to transmit trace context between services: + - **HTTP headers**: `sentry-trace` and `baggage` headers on outgoing HTTP requests. + - **Metadata**: `sentry-trace` and `baggage` as metadata on queue messages (details are queue-specific). + - **Environment variables**: `SENTRY_TRACE` and `SENTRY_BAGGAGE` when calling another process. + +--- + +## Behavior + + + +### Outgoing Propagation + +SDKs **MUST** propagate trace context to downstream services by adding `sentry-trace` and `baggage` to outgoing requests via one of the supported [carriers](#concepts). + +The `sentry-trace` and `baggage` headers **MUST** only be attached to an outgoing request if the request URL matches the [`tracePropagationTargets`](#trace-propagation-targets) option (or if the option is `null` / not set). + + + + + +### Incoming Propagation + +SDKs **MUST** pick up incoming trace information by: +- Reading `sentry-trace` and `baggage` headers for each incoming HTTP request. +- Reading `sentry-trace` and `baggage` metadata when retrieving an item from a queue. +- Reading the environment variables `SENTRY_TRACE` and `SENTRY_BAGGAGE` on startup. + +This trace information **MUST** be stored in the propagation context of the current scope, ensuring all telemetry emitted from the receiving service includes the correct trace information. + + + + + +### tracePropagationTargets + +SDKs **MUST** expose a `tracePropagationTargets` option that controls which outgoing HTTP requests receive trace headers. This option takes an array of strings and/or regular expressions. + +SDKs **MUST** only add trace headers to an outgoing request if the request's URL matches the regex or, in the case of string literals, contains at least one of the items from the array. String literals do not have to be full matches — the URL of a request is matched when it *contains* a string provided through the option. + +SDKs **MAY** choose a default value which makes sense for their use case. Most SDKs default to `.*` (attach headers to all outgoing requests), but deviation is allowed. For example, because of CORS, browser-based SDKs default to only adding headers to domain-internal requests. + +#### Example + +```JS +// Entries can be strings or regex +tracePropagationTargets: ['localhost', /^\// ,/myApi.com\/v[2-4]/] + +URLs matching: 'localhost:8443/api/users', 'mylocalhost:8080/api/users', '/api/envelopes', 'myApi.com/v2/projects' +URLs not matching: 'someHost.com/data', 'myApi.com/v1/projects' +``` + + + +This option replaces the non-standardized `tracingOrigins` option which was previously used in some SDKs. SDKs that support `tracingOrigins` are encouraged to deprecate and eventually remove `tracingOrigins` in favour of `tracePropagationTargets`. In case both options are specified by users, SDKs **SHOULD** only rely on the `tracePropagationTargets` array. + + + + + + + +### strictTraceContinuation + +This **MUST** be a boolean value. Default is `false`. This option controls trace continuation from unknown 3rd party services that happen to be instrumented by a Sentry SDK. + +If the SDK is able to parse an org ID from the configured DSN, it **MUST** be propagated as a baggage entry with the key `sentry-org_id`. Given a DSN of `https://1234@o1.ingest.us.sentry.io/1`, the org ID is `1`, based on `o1`. + +Additionally, the SDK **MUST** be configurable with an optional `orgId: ` setting that takes precedence over the parsed value from the DSN. This option **SHOULD** be set when running a self-hosted version of Sentry or if a non-standard Sentry DSN is used, such as when using a local Relay. + +On incoming traces, the SDK **MUST** compare the `sentry-org_id` baggage value against its own parsed value from the DSN or org setting. Only if both match, the trace is continued. If there is no match, neither the trace ID, the parent sampling decision nor the baggage **SHOULD** be taken into account. The SDK **SHOULD** behave like it is the head of trace in this case. + +This behavior can be disabled by setting `strictTraceContinuation: false` in the SDK init call. Initially, SDKs **MUST** introduce this option with a default value of `false`. Once the majority of SDKs have introduced this option, the default value will change to `true` (in a major version bump), making it opt-out. + +Regardless of `strictTraceContinuation` being set to `true` or `false`, if the SDK is either configured with an `org` or was able to parse the value from the DSN, incoming traces containing an `org` value in the baggage that does not match the one from the receiving SDK, the trace is not continued. + +#### Examples + +| Baggage `sentry-org` | SDK `org` | `strictTraceContinuation` | Result | +| --- | --- | :---: | --- | +| 1 | 1 | false | continue trace | +| none | 1 | false | continue trace | +| 1 | none | false | continue trace | +| none | none | false | continue trace | +| 1 | 2 | false | start new trace | +| 1 | 1 | true | continue trace | +| none | 1 | true | start new trace | +| 1 | none | true | start new trace | +| none | none | true | continue trace | +| 1 | 2 | true | start new trace | + + + + + +### propagateTraceparent + +This **MUST** be a boolean value. The default is `false`. This option enables the propagation of the W3C Trace Context HTTP header `traceparent` on outgoing HTTP requests. + +The `traceparent` header **MUST** only be sent when `propagateTraceparent` is `true` and the request matches `tracePropagationTargets` (same condition as for `sentry-trace`/`baggage`). + +Header Format: +- Key: `traceparent` +- Value: `00---` where `` is `01` if sampled, otherwise `00`. + +The full spec is available in the [W3C Trace Context](https://www.w3.org/TR/trace-context/) specification. + + + + + +### Propagated Random Value + +To improve the likelihood of capturing complete traces when backend services use a custom sample rate via `tracesSampler`, the SDK propagates the same random value used for sampling decisions across all services in a trace. This ensures consistent sampling decisions across a trace instead of generating a new random value for each service. + +The random value (`sample_rand`) is set according to the following rules: + +1. A `sample_rand` is a float (`0.123456` notation) in the range of `[0, 1)` (including 0.0, excluding 1.0), with six digits after the decimal point. +1. When tracing is enabled and a new trace is started, the SDK generates a `sample_rand` value for the current execution context. + 1. This also applies to default propagation mode (no tracing config) where the SDK simply generates `sample_rand` every time a new trace is started. This `sample_rand` value can then be stored on `PropagationContext`. +1. It is _recommended_ to generate the random number deterministically using the trace ID as seed or source of randomness (make sure to do this atomically so multiple threads accessing the same random instance don't mix their seeds). The exact method by which the random number is created is implementation-defined and **MAY** vary between SDK implementations. +1. The `sample_rand` is part of the DSC (Dynamic Sampling Context) and as with other values on the `baggage` header, the `sample_rand` value from the current execution context **SHOULD** be propagated to downstream SDKs. It **SHOULD** also be sent to other systems as part of the `baggage` header if Performance is disabled and sampling decision is deferred. +1. On incoming traces, an SDK takes the incoming `sentry-sample_rand` value in the `baggage` header and uses it for the rest of the current execution context (for example, request) by storing it in the `PropagationContext`. +1. If `sample_rand` is missing on an incoming trace, the SDK creates a new one applying **special rules** and uses it for the current execution context: + 1. If `sample_rate` (inside `baggage`) and the sampling decision (trailing `-1` or `-0` from the `sentry-trace` header) are present in the incoming trace, create `sample_rand` so that when compared to the incoming `sample_rate` it would lead to the same sampling decision that is in the `sentry-trace` header. This means, for a decision of `True` generate a random number in half-open range `[0, rate)` and for a decision of `False` generate a random number in range `[rate, 1)`. + 1. If the sampling decision is missing on the incoming trace, generate a random number in range of `[0, 1)` (including 0.0, excluding 1.0), like for a new trace. + +The SDK **SHOULD** always use the stored random number (`sentry-sample_rand`) for sampling decisions and **SHOULD NOT** directly rely on `math.random()` when deciding to sample or not: + +1. When the `tracesSampler` is invoked, the return value **SHOULD** be compared with `sample_rand`: `trace["sentry-sample_rand"] < tracesSampler(context)` +1. When there is an incoming trace, the SDK fully inherits incoming sampling decisions from the `sentry-trace` header. +1. Otherwise, when the SDK is the head of a trace (and `tracesSampleRate` is defined), the sampling is done comparing the `tracesSampleRate` with the `sample_rand`: `trace["sentry-sample_rand"] < config.tracesSampleRate` + +Something that **SHOULD** be documented for every SDK is the recommended way to use a `tracesSampler` to inherit the parent's sampling decision using the `parentSampleRate`. This way, Sentry can still extrapolate counts correctly: + +```js +tracesSampler: ({ name, parentSampleRate }) => { + // Inherit the trace parent's sample rate if there is one. Sampling is deterministic + // for one trace, i.e. if the parent was sampled, we will be sampled too at the same + // rate. + if (typeof parentSampleRate === "number") { + return parentSampleRate; + } + + // Else, use default sample rate (replacing tracesSampleRate). + return 0.5; +}, +``` + + + + + +### Sampling Decision Propagation + +A transaction's sampling decision **MUST** be passed to all of its children, including across service boundaries. This can be accomplished in the `startChild` method for same-service children and using the `sentry-trace` header for children in a different service. + + + + + +### Default Propagation (No Tracing Config) + +If Sentry SDKs are not configured for sending spans (i.e. no `tracesSampleRate` or `tracesSampler`), they **MUST** fall back to a mode where they still handle continuing and propagating traces. Internally, this mode is referred to as "Tracing without Performance" (TwP). + +This means that SDKs by default always: + +- Continue incoming traces +- Attach `event.contexts.trace` context on events (e.g. errors, check-ins, replays) +- Attach the `trace` envelope header to Sentry envelopes, populated from the [dynamic sampling context](/sdk/foundations/trace-propagation/dynamic-sampling-context/) +- Propagate trace data (`sentry-trace`, `baggage`) via the usual [carriers](#concepts), with the correct [sampling decision](#deferred-sampling) + +Setting `tracesSampleRate: 0` does **not** fall back to this mode. Instead, sampling decisions are always negative and the trace is propagated with a negative sampling decision. + +To opt out of further propagating a trace, users can pass an empty array (or language-equivalent parameter) to [`tracePropagationTargets`](#trace-propagation-targets). This prevents the SDK from propagating trace information further. Note that for incoming requests with trace headers, SDKs **SHOULD** still continue the trace but not propagate it further downstream. + + + + + +### Deferred Sampling + +If an SDK in default propagation mode doesn't receive an incoming trace, it **SHOULD** start a new trace. In this case, the new trace is not sampled (as in, there is no sampling decision, neither positive nor negative). Instead, the sampling decision is _deferred_ to the next downstream SDK. + +This means that: + +- The SDK **MUST NOT** include a sampled flag in the [`sentry-trace` header](#sentry-trace-header), meaning the header has the format `-`. +- The [dynamic sampling context](/sdk/foundations/trace-propagation/dynamic-sampling-context/), propagated via `baggage`, **MUST NOT** contain the `sentry-sampled` key. + +For SDKs starting a new trace in this mode, the [Dynamic Sampling Context](/sdk/foundations/trace-propagation/dynamic-sampling-context/) **SHOULD** be lazily populated and frozen for the duration of the trace. Given that no span is actually available, the DSC will not contain any keys related to spans (`transaction`, `sample_rate`, or `sampled`). + + + + + +### Trace Data on Events and Envelopes + +Any event created by an SDK **MUST** include the [`trace` context](/sdk/foundations/transport/event-payloads/contexts/#trace-context). This context **SHOULD** contain the trace data of the current trace, if available, just like in regular tracing mode. + +Furthermore, the [`trace` envelope header](/sdk/foundations/trace-propagation/dynamic-sampling-context/#envelope-header) (populated from the dynamic sampling context) **MUST** be attached to any outgoing event envelope. + +#### Trace Duration and Storage + +Traces **SHOULD** have the same duration as regular traces. For example, a trace for a backend server **SHOULD** generally last for the duration of one individual request. This usually corresponds with the lifetime of an [isolation scope](/sdk/foundations/state-management/scopes/#isolation-scope). + +SDKs **MUST** store trace data in a way that makes it possible for them to be attached to events and propagated to outgoing requests. The exact storage mechanism is up to the SDK implementation, but we recommend storing the data on the scope in a field called `propagationContext`. + +The `propagationContext` **SHOULD** be populated with a random `traceId` and `spanId` if no incoming trace is present. This — in combination with the [`sentry-trace` header specification](#sentry-trace-header) requiring a `spanId` — means a non-existing `spanId` will be propagated along with the trace and attached to events. While not ideal, we accept this limitation as the Sentry product can and **SHOULD** handle non-existing (parent) spans. + +In SDKs adapting OpenTelemetry's tracing capabilities ([POTel](/sdk/foundations/state-management/scopes/#otel-context-alignment)), trace data could also be stored in a non-recording span. Note that in the case of using the non-recording span, the span is also not sampled, meaning the sampling decision **MUST** still be [deferred](#deferred-sampling) when starting a new trace. + + + +--- + +## Wire Format + + + +### sentry-trace Header + +The `sentry-trace` header is used for trace propagation. SDKs use it to continue traces from upstream services (incoming HTTP requests) and to propagate tracing information to downstream services (outgoing HTTP requests). + +`sentry-trace = traceid-spanid-sampled` + +`sampled` is optional. So at a minimum, it's expected: + +`sentry-trace = traceid-spanid` + +To offer minimal compatibility with the [W3C `traceparent` header](https://www.w3.org/TR/trace-context/#traceparent-header) (without the version prefix) and [Zipkin's `b3` headers](https://zipkin.io/pages/instrumenting#communicating-trace-information) (which consider both 64 and 128 bits for `traceId` valid), the `sentry-trace` header **SHOULD** have a `traceId` of 128 bits encoded in 32 hex chars and a `spanId` of 64 bits encoded in 16 hex chars. To avoid confusion with the W3C `traceparent` header (to which our header is similar but not identical), we call it simply `sentry-trace`. No version is being defined in the header. + +The `sentry-trace` header **MUST** only be attached to an outgoing request if the request's URL matches at least one entry of the [`tracePropagationTargets`](#trace-propagation-targets) option or this option is set to `null`. + + + + + +### The sampled Value + +To simplify processing, the value consists of a single (optional) character. The possible values are: + +``` + - No value means defer + +0 - Don't sample + +1 - Sampled +``` + +Unlike with `b3` headers, a `sentry-trace` header **MUST** never consist solely of a sampling decision, with no `traceid` or `spanid` values. There are [good reasons](https://github.com/apache/incubator-zipkin-b3-propagation/blob/bc937b6854ea30e46b3e85fbf147d8f4de685dd5/README.md#why-send-trace-ids-with-a-reject-sampling-decision) to always include the `traceid` and `spanid` regardless of the sampling decision, and doing so also simplifies implementation. + +Besides the [usual reasons to use \*defer](https://github.com/apache/incubator-zipkin-b3-propagation/blob/bc937b6854ea30e46b3e85fbf147d8f4de685dd5/README.md#why-defer-a-sampling-decision),\* in the case of Sentry, a reason would be if a downstream system captures an error event with Sentry. The decision could be done at that point to sample that trace in order to have tracing data available for the reported crash. + + + + + +### W3C traceparent Header + +To interoperate with OpenTelemetry (OTel) services, SDKs can optionally send the W3C Trace Context `traceparent` HTTP header on outgoing requests in addition to Sentry's own `sentry-trace` and `baggage`. This enables traces originating from a Sentry SDK to be continued by components that only use OTel/W3C propagation. + +The `traceparent` header **MUST** only be sent when [`propagateTraceparent`](#propagate-traceparent) is `true` and the request matches [`tracePropagationTargets`](#trace-propagation-targets) (same condition as for `sentry-trace`/`baggage`). + +The full spec is available in the [W3C Trace Context](https://www.w3.org/TR/trace-context/) document. + + + + + +### Environment Variables + +When propagating trace context by launching a subprocess, the environment variables `SENTRY_TRACE` and `SENTRY_BAGGAGE` **SHOULD** be set. The values **MUST** match what would be set for the corresponding HTTP headers. + + + +--- + +## Public API + + + +### continueTrace + +To continue a trace from an upstream service, the SDK **MUST** expose a method to extract the traceparent and baggage information and apply these to the applicable scope. The method **MUST NOT** create a new segment span on its own. + +```js +Sentry.continueTrace({ + sentryTrace: request.headers['sentry-trace'], + baggage: request.headers['baggage'], +}, () => { + Sentry.startSpan({ name: 'test' }, () => { + // .... + }); +}) +``` + +```python +sentry_sdk.continue_trace(request.headers) + +with sentry_sdk.start_span(name="test"): + ... +``` + +Newly created root spans **SHOULD** now contain these properties, such as `trace_id` and `parent_span_id`. + +The exact function signature of the `continueTrace` function depends on what's canonical in the SDK. It **MAY** require explicitly passing `sentry-trace` and `baggage`, or it **MAY** allow providing a dictionary of headers/environment variables. + + + + + +### getTraceData + +To propagate a trace to a downstream service, the SDK **MUST** expose methods to fetch the required information to allow the next service to continue the trace. + +```js +const traceData = Sentry.getTraceData() +``` + +```python +traceparent = sentry_sdk.get_traceparent() +baggage = sentry_sdk.get_baggage() +``` + + + + + +### startNewTrace + +The SDK **MUST** offer a method to clear trace propagation data, allowing to create spans with a fresh new trace. + +```js +Sentry.startNewTrace(() => { + Sentry.startSpan({ name: 'segment under trace 1' }, () => {...}); +}) + +Sentry.startNewTrace(() => { + Sentry.startSpan({ name: 'segment under trace 2' }, () => {...}); +}) +``` + +```python +import sentry_sdk + +with sentry_sdk.start_span(name="segment under trace 1"): + ... + +sentry_sdk.new_trace() + +# The next span started after new_trace() will NOT continue the same trace: +with sentry_sdk.start_span(name="segment under trace 2"): + ... +``` + + + +--- + +## Reference + + + +### Propagation Decision Matrix + +This matrix shows how trace propagation works in SDKs under different scenarios. + +**Column definitions:** + +Scenario (inputs): +- **Incoming trace**: Whether `sentry-trace`/`baggage` headers are present on the incoming request. +- **Incoming sampled**: The sampled flag from the incoming `sentry-trace` header (`1` = sampled, `0` = not sampled, `deferred` = no value). +- **`tracePropagationTargets` match**: Whether the outgoing request URL matches the `tracePropagationTargets` option. +- **`tracesSampleRate`**: The configured sample rate (`null` = tracing not enabled, `0` = 0%, `1` = 100%). + +Outcome (results): +- **Send spans?**: Whether the SDK sends span/transaction data to Sentry. +- **Outgoing trace?**: Whether `sentry-trace`/`baggage` headers are added to outgoing requests. +- **Continue trace?**: Whether the outgoing `trace_id` matches the incoming `trace_id`. + +| Incoming trace | Incoming sampled | `tracePropagationTargets` match | `tracesSampleRate` | Send spans? | Outgoing trace? | Continue trace? | +| --- | :---: | :---: | :---: | :---: | :---: | :---: | +| not present | - | yes | null | no | yes | - | +| not present | - | yes | 0 | no | yes | - | +| not present | - | yes | 1 | yes | yes | - | +| not present | - | no | null | no | no | - | +| not present | - | no | 0 | no | no | - | +| not present | - | no | 1 | yes | no | - | +| present | deferred | yes | null | no | yes | yes | +| present | deferred | yes | 0 | no | yes | yes | +| present | deferred | yes | 1 | yes | yes | yes | +| present | 1 | yes | null | no | yes | yes | +| present | 1 | yes | 0 | yes | yes | yes | +| present | 1 | yes | 1 | yes | yes | yes | +| present | 0 | yes | null | no | yes | yes | +| present | 0 | yes | 0 | no | yes | yes | +| present | 0 | yes | 1 | no | yes | yes | +| present | deferred | no | null | no | no | - | +| present | deferred | no | 0 | no | no | - | +| present | deferred | no | 1 | yes | no | - | +| present | 1 | no | null | no | no | - | +| present | 1 | no | 0 | yes | no | - | +| present | 1 | no | 1 | yes | no | - | +| present | 0 | no | null | no | no | - | +| present | 0 | no | 0 | no | no | - | +| present | 0 | no | 1 | no | no | - | + +#### FAQ + +**Why are we sometimes sampling even if `tracesSampleRate` is 0? Why are we sometimes unsampling if `tracesSampleRate` is 1?** + +A `tracesSampleRate` between 0 and 1 is only taken into account if there is no incoming trace and the SDK has to make its own sampling decision. If there is an incoming trace, the parent sampling decision always takes precedence over `tracesSampleRate`. + + + +--- + +## Changelog + + diff --git a/develop-docs/sdk/foundations/transport/event-payloads/contexts.mdx b/develop-docs/sdk/foundations/transport/event-payloads/contexts.mdx index 1137b18ce7953..df04797b384e6 100644 --- a/develop-docs/sdk/foundations/transport/event-payloads/contexts.mdx +++ b/develop-docs/sdk/foundations/transport/event-payloads/contexts.mdx @@ -771,7 +771,7 @@ Additional information that allows Sentry to connect multiple transactions, span `span_id` -: _Required_. The ID of the span or transaction. For non-transaction events, and if performance monitoring is disabled, it may still be desired to attach events to a trace via a trace ID. In these cases, you still need to provide a span ID. This span ID can effectively be entirely random and doesn't need to relate to an actual span, however, it is recommended to consider using the same span ID for multiple events within the same unit-of-execution (e.g. a request). [See the TwP docs](/sdk/telemetry/traces/tracing-without-performance/#attaching-trace-data-to-events-and-envelopes) for more details. +: _Required_. The ID of the span or transaction. For non-transaction events, and if performance monitoring is disabled, it may still be desired to attach events to a trace via a trace ID. In these cases, you still need to provide a span ID. This span ID can effectively be entirely random and doesn't need to relate to an actual span, however, it is recommended to consider using the same span ID for multiple events within the same unit-of-execution (e.g. a request). [See the context propagation docs](/sdk/foundations/trace-propagation/#trace-data-on-events) for more details. - Example: `"bb8f278130535c3c"` diff --git a/develop-docs/sdk/getting-started/standards/api-architecture.mdx b/develop-docs/sdk/getting-started/standards/api-architecture.mdx index a1fe8a5a5b0f1..5d4f33add7b1b 100644 --- a/develop-docs/sdk/getting-started/standards/api-architecture.mdx +++ b/develop-docs/sdk/getting-started/standards/api-architecture.mdx @@ -16,10 +16,10 @@ sidebar_order: 1 -## Server-side (Relay) vs. SDK-side decision gate - +## Server-side (Relay) vs. SDK-side decision gate + #### Rule New processing or transformation logic **MUST** default to server-side (Relay). @@ -47,10 +47,10 @@ SDK-specific. --- -## SDK-side logic must not break on server changes - +## SDK-side logic must not break on server changes + #### Rule SDKs typically outlive individual API versions, so forward compatibility is essential to prevent ecosystem breakage. @@ -77,10 +77,10 @@ They **MUST NOT** fail due to additive changes. Unknown fields, categories, or d --- -## Public API change approval gate - +## Public API change approval gate + #### Rule Any change to public API (add, change, deprecate, remove) **REQUIRES** @sdk-leads approval. Public API includes anything a user can call, import, configure, subclass, or otherwise reference. If there is any doubt whether something is public, check for usage in public repositories using the SDK. When still unsure, treat it as public. @@ -103,10 +103,10 @@ requirement is universal. --- -## Semantic conventions process - +## Semantic conventions process + #### Rule New attributes **MUST** first be defined in [sentry-conventions](https://github.com/getsentry/sentry-conventions). @@ -130,10 +130,10 @@ Process: --- -## Breaking change process - +## Breaking change process + #### Rule Breaking changes **MUST** follow the breaking changes playbook. @@ -167,10 +167,10 @@ universal. --- -## Deprecation lifecycle - +## Deprecation lifecycle + #### Rule All deprecations of public APIs, user-facing integrations, and supported platforms or frameworks follow three stages: diff --git a/develop-docs/sdk/getting-started/standards/code-quality.mdx b/develop-docs/sdk/getting-started/standards/code-quality.mdx index 8502f77805009..b8fdf2ac3d1fc 100644 --- a/develop-docs/sdk/getting-started/standards/code-quality.mdx +++ b/develop-docs/sdk/getting-started/standards/code-quality.mdx @@ -16,10 +16,10 @@ sidebar_order: 3 -## Linting and Formatting in CI - +## Linting and Formatting in CI + #### Rule Every SDK repo **MUST** have automated linting and formatting in CI. Code that doesn't pass **MUST NOT** merge. There are no exceptions to this requirement. @@ -41,10 +41,10 @@ that a linter exists and is enforced. --- -## Type Checking in CI - +## Type Checking in CI + #### Rule Type checking is **REQUIRED** in CI for: @@ -67,10 +67,10 @@ with a tracked plan. --- -## Test Requirements by Change Type - +## Test Requirements by Change Type + #### Rule - **Bug fix**: regression test (fails without fix, passes with it). @@ -97,10 +97,10 @@ with a tracked plan. --- -## Test Quality - +## Test Quality + #### Rule Tests **MUST** assert meaningful behavior: @@ -132,10 +132,10 @@ anti-patterns documented per-SDK in AGENTS.md. --- -## Dependency Management - +## Dependency Management + #### Rule - New dependency **REQUIRES** explicit justification in the PR description @@ -162,10 +162,10 @@ See also: [Adding a Dependency](/sdk/getting-started/playbooks/development/addin --- -## SDK Size and Performance Budgets - +## SDK Size and Performance Budgets + #### Rule Each SDK **MUST** define and track: @@ -187,10 +187,10 @@ standard is that budgets exist and are tracked. --- -## Security Practices - +## Security Practices + #### Rule No secrets, credentials, or PII in code or commits. Data handling follows the [data handling spec](/sdk/expected-features/data-handling/). Security-sensitive changes **REQUIRE** explicit review from someone with security context. Vulnerability patch SLAs: critical 48h, high 1 week, medium next release. Dependency vulnerability alerts **MUST NOT** be ignored or silently dismissed. diff --git a/develop-docs/sdk/getting-started/standards/code-submission.mdx b/develop-docs/sdk/getting-started/standards/code-submission.mdx index 0ff5b51a8b6fe..0b0e8d480f83f 100644 --- a/develop-docs/sdk/getting-started/standards/code-submission.mdx +++ b/develop-docs/sdk/getting-started/standards/code-submission.mdx @@ -16,10 +16,10 @@ sidebar_order: 2 -## Commit message format - +## Commit message format + #### Rule ``` @@ -61,10 +61,10 @@ For additional context on commit message best practices, see [Commit Messages](/ --- -## Branch naming - +## Branch naming + #### Rule `/` (e.g., `feat/add-client-reports`, `fix/rate-limit-parsing`). @@ -85,10 +85,10 @@ For additional context on commit message best practices, see [Commit Messages](/ --- -## PR description quality - +## PR description quality + #### Rule Every PR **MUST** include a description with: @@ -119,10 +119,10 @@ requirements are universal. --- -## PR draft mode - +## PR draft mode + #### Rule PRs **MUST** be created as drafts. Mark ready when CI passes and description is complete. @@ -144,10 +144,10 @@ PRs **MUST** be created as drafts. Mark ready when CI passes and description is --- -## Changelog entry - +## Changelog entry + #### Rule User-facing changes (`feat`, `fix`, `perf`, breaking) **REQUIRE** a changelog entry. Internal changes exempt. Override with `skip-changelog` label. @@ -164,10 +164,10 @@ User-facing changes (`feat`, `fix`, `perf`, breaking) **REQUIRE** a changelog en --- -## Keep PRs focused - +## Keep PRs focused + #### Rule A PR **SHOULD** do one thing — and do it well. Avoid mixing functional changes with unrelated refactors, cleanup, or reorganizations. If the work falls into distinct categories, split it into multiple PRs. Smaller, focused PRs are easier to review, reason about, and revert. @@ -189,10 +189,10 @@ A PR **SHOULD** do one thing — and do it well. Avoid mixing functional changes --- -## AI attribution - +## AI attribution + #### Rule AI-generated changes get `Co-Authored-By` in commit footer (e.g., `Co-Authored-By: Claude `). This is the only AI involvement indicator. "Generated by AI" or similar markers **MUST NOT** appear anywhere. diff --git a/develop-docs/sdk/getting-started/standards/coordination-maintenance.mdx b/develop-docs/sdk/getting-started/standards/coordination-maintenance.mdx index 94325d7a47e53..169a5f7e2b48d 100644 --- a/develop-docs/sdk/getting-started/standards/coordination-maintenance.mdx +++ b/develop-docs/sdk/getting-started/standards/coordination-maintenance.mdx @@ -16,10 +16,10 @@ sidebar_order: 7 -## Cross-SDK Coordination Protocol - +## Cross-SDK Coordination Protocol + #### Rule Multi-SDK changes follow: @@ -43,10 +43,10 @@ Multi-SDK changes follow: --- -## Triaging SLA - +## Triaging SLA + #### Rule All user-reported issues **MUST** receive substantive first response within 2 business days. @@ -65,10 +65,10 @@ Substantive means acknowledging the problem, asking for reproduction steps, conf --- -## Platform/language version support policy - +## Platform/language version support policy + #### Rule - Supported versions documented in README and docs @@ -90,10 +90,10 @@ universal. --- -## Post-release monitoring - +## Post-release monitoring + #### Rule After each release: @@ -116,10 +116,10 @@ After each release: --- -## Rollback procedures - +## Rollback procedures + #### Rule Every SDK **MUST** have documented rollback: diff --git a/develop-docs/sdk/getting-started/standards/release-versioning.mdx b/develop-docs/sdk/getting-started/standards/release-versioning.mdx index cbd8053b04a80..64d57eb98dc74 100644 --- a/develop-docs/sdk/getting-started/standards/release-versioning.mdx +++ b/develop-docs/sdk/getting-started/standards/release-versioning.mdx @@ -16,10 +16,10 @@ sidebar_order: 99 -## Version Format - +## Version Format + #### Rule All SDK versions **MUST** follow [semantic versioning (SemVer)](https://semver.org/): @@ -43,10 +43,10 @@ around SemVer (if applicable) are allowed. --- -## Pre-Release Identifiers - +## Pre-Release Identifiers + #### Rule Pre-release identifiers **MUST** be one of: `preview`, `pre`, `rc`, `dev`, `alpha`, `beta`, `unstable`, `a`, `b`. Arbitrary strings are not accepted. @@ -86,10 +86,10 @@ Invalid (treated as stable): --- -## Build Identifiers - +## Build Identifiers + #### Rule Build identifiers **MAY** be appended for platform or architecture variants. When combined with pre-release identifiers, the pre-release **MUST** come first. @@ -121,10 +121,10 @@ platform-specific artifacts. --- -## Release Tooling - +## Release Tooling + #### Rule SDKs **MUST** use [craft](https://github.com/getsentry/craft) for release preparation and [publish](https://github.com/getsentry/publish) for release approval. Every SDK repo **MUST** have: @@ -149,10 +149,10 @@ SDK-specific. Toolchain is universal. --- -## Merge Target - +## Merge Target + #### Rule By default, releases are merged to the repository's default branch (usually `main`). To override this, pass the `merge_target` input in the release workflow: @@ -181,10 +181,10 @@ Add a corresponding `merge_target` input to the workflow's `workflow_dispatch.in --- -## Multiple Craft Configs Per Repository - +## Multiple Craft Configs Per Repository + #### Rule When a repository maintains multiple major versions (e.g., v7 and v8) with diverging publishing targets, it can opt into using the `.craft.yml` from the merge target branch instead of the default branch. diff --git a/develop-docs/sdk/getting-started/standards/repository-docs.mdx b/develop-docs/sdk/getting-started/standards/repository-docs.mdx index 8b266f8a8daee..89cc301859ee0 100644 --- a/develop-docs/sdk/getting-started/standards/repository-docs.mdx +++ b/develop-docs/sdk/getting-started/standards/repository-docs.mdx @@ -16,10 +16,10 @@ sidebar_order: 5 -## AGENTS.md - +## AGENTS.md + #### Rule Every SDK repo **MUST** have `AGENTS.md` covering: @@ -48,10 +48,10 @@ Every SDK repo **MUST** have `AGENTS.md` covering: --- -## CONTRIBUTING.md - +## CONTRIBUTING.md + #### Rule Every SDK repo **MUST** have `CONTRIBUTING.md` covering: @@ -77,10 +77,10 @@ sections use shared template. --- -## PR Template - +## PR Template + #### Rule Every SDK repo **MUST** have a GitHub PR template with description structure guidance and linked-issue reminder. The template **SHOULD** be minimal, providing guidance rather than enforcing rigid structure with mandatory sections. @@ -101,10 +101,10 @@ Every SDK repo **MUST** have a GitHub PR template with description structure gui --- -## Documentation-with-Code - +## Documentation-with-Code + #### Rule User-facing changes **REQUIRE** corresponding docs: @@ -129,10 +129,10 @@ SDK PR links to docs PR. Neither merges without the other being at least approve --- -## AI Context File Maintenance - +## AI Context File Maintenance + #### Rule AI context files (AGENTS.md, `.cursorrules`, `.github/copilot-instructions.md`, CLAUDE.md) **MUST** be maintained as living documentation: updated with architectural changes, reviewed quarterly, periodically tested by having an AI tool attempt a contribution. diff --git a/develop-docs/sdk/getting-started/standards/review-ci.mdx b/develop-docs/sdk/getting-started/standards/review-ci.mdx index ad00b4d860948..07bcb7d292018 100644 --- a/develop-docs/sdk/getting-started/standards/review-ci.mdx +++ b/develop-docs/sdk/getting-started/standards/review-ci.mdx @@ -16,10 +16,10 @@ sidebar_order: 4 -## Required Reviewers - +## Required Reviewers + #### Rule Every PR **REQUIRES** at least one approving review. @@ -49,10 +49,10 @@ Every PR **REQUIRES** at least one approving review. --- -## Review SLAs - +## Review SLAs + #### Rule Internal PRs: first review within 1 business day. @@ -75,10 +75,10 @@ If an area has only a single reviewer or if that reviewer lacks capacity, the re --- -## Review Feedback Conventions - +## Review Feedback Conventions + #### Rule LOGAF scale: @@ -106,10 +106,10 @@ Comments without a prefix are treated as `m:` (medium). A PR **MUST NOT** be mer --- -## Required CI Checks Baseline - +## Required CI Checks Baseline + #### Rule Every SDK repo **MUST** have as required status checks: @@ -143,10 +143,10 @@ Optional/**RECOMMENDED**: --- -## Release Gating Criteria - +## Release Gating Criteria + #### Rule A release **MUST NOT** ship if: diff --git a/develop-docs/sdk/platform-specifics/native-sdks/tracing.mdx b/develop-docs/sdk/platform-specifics/native-sdks/tracing.mdx index 3610941dcf7aa..9657dce047f52 100644 --- a/develop-docs/sdk/platform-specifics/native-sdks/tracing.mdx +++ b/develop-docs/sdk/platform-specifics/native-sdks/tracing.mdx @@ -8,7 +8,7 @@ og_image: /og-images/sdk-platform-specifics-native-sdks-tracing.png In the Native SDK we have the following scenarios, showcasing how trace-context data flows: ### Tracing without Performance -In Tracing without Performance ([TwP](https://develop.sentry.dev/sdk/telemetry/traces/tracing-without-performance/)) the SDK does not create spans. However, we still want to connect events across boundaries so we use a `propagation_context` to store the relevant data (a `trace_id` and a `span_id`) which gets generated during SDK initialization. This `propagation_context` can be updated by calling `sentry_set_trace()`, for example from a downstream SDK. +In Tracing without Performance ([TwP](https://develop.sentry.dev/sdk/foundations/trace-propagation/#default-propagation)) the SDK does not create spans. However, we still want to connect events across boundaries so we use a `propagation_context` to store the relevant data (a `trace_id` and a `span_id`) which gets generated during SDK initialization. This `propagation_context` can be updated by calling `sentry_set_trace()`, for example from a downstream SDK. ### Tracing with Performance When any [traces sampling option](https://docs.sentry.io/platforms/native/configuration/sampling/#configuring-the-transaction-sample-rate) is enabled, the SDK can send spans. Just like in TwP, we still use a `propagation_context` to store the relevant data (a `trace_id` and a `span_id`). Now, events and spans can be connected through a common `trace_id` and, if a span is scoped, it will additionally be connected hierarchically to the event through its `span_id`. By default, both spans and events will inherit the `trace_id` from the `propagation_context` as generated during SDK initialization. diff --git a/develop-docs/sdk/telemetry/attachments.mdx b/develop-docs/sdk/telemetry/attachments.mdx index a25acaf57ec13..6617854595626 100644 --- a/develop-docs/sdk/telemetry/attachments.mdx +++ b/develop-docs/sdk/telemetry/attachments.mdx @@ -81,10 +81,10 @@ Trace attachments (experimental) are associated with a **trace** via `trace_id` ## Behavior -### Standard Attachments - +### Standard Attachments + Envelope item type `"attachment"`. Contains the raw payload of an attachment file, always associated with an event or transaction. **Constraints:** @@ -97,10 +97,10 @@ Envelope item type `"attachment"`. Contains the raw payload of an attachment fil -### Attachment Types - +### Attachment Types + The `attachment_type` header declares the special type of an attachment. Possible values: | Type | Since | Description | @@ -114,10 +114,10 @@ The `attachment_type` header declares the special type of an attachment. Possibl -### Screenshots - +### Screenshots + When the user opts in, SDKs with a user interface (mobile, desktop) **SHOULD** take a screenshot of the application during a crash or error and include it as an attachment in the envelope with the event. This is inherently a best-effort feature. Some environments restrict UI access during hard crashes — for example, iOS does not allow running Objective-C code after a signal break, so hard crash screenshot capture is not possible there. @@ -134,10 +134,10 @@ Whenever possible, SDKs **SHOULD** avoid adding the attachment altogether if tak -### View Hierarchy - +### View Hierarchy + SDKs **MAY** attach a `view-hierarchy.json` file following the structure described in [RFC #33](https://github.com/getsentry/rfcs/blob/main/text/0033-view-hierarchy.md). The attachment **MUST** use `attachment_type: "event.view_hierarchy"` and `content_type: "application/json"`. For native SDKs (since 1.4.0), the path to the view hierarchy file **SHOULD** be configurable at SDK initialization. The SDK monitors the file and uploads it along with any event or crash: @@ -154,10 +154,10 @@ When using `Crashpad` as the crash-capturing backend in the Native SDK, the file -### Trace Attachments - +### Trace Attachments + Trace attachments are an experimental feature that is still under development. @@ -166,14 +166,14 @@ Trace attachments use item type `"attachment"` with content type `"application/v **Envelope headers:** -- `trace` *(optional)*: If the envelope containing the trace attachment has a [Dynamic Sampling Context](/sdk/telemetry/traces/dynamic-sampling-context), it will be subject to trace-based dynamic sampling rules and potentially dropped. +- `trace` *(optional)*: If the envelope containing the trace attachment has a [Dynamic Sampling Context](/sdk/foundations/trace-propagation/dynamic-sampling-context/), it will be subject to trace-based dynamic sampling rules and potentially dropped. -### Attachment Placeholders - +### Attachment Placeholders + Attachment placeholders are an experimental feature, the protocol is subject to change. @@ -200,10 +200,10 @@ SDKs **SHOULD** send placeholders in the same envelope as the event the file is ## Wire Format -### Standard Attachment Item - +### Standard Attachment Item + **Envelope headers:** | Field | Type | Required | Since | Description | @@ -222,10 +222,10 @@ SDKs **SHOULD** send placeholders in the same envelope as the event the file is -### Attachment Placeholder Item - +### Attachment Placeholder Item + **Envelope headers:** | Field | Type | Required | Description | @@ -260,10 +260,10 @@ The item header **MAY** also contain `attachment_type` and the original file's ` -### Trace Attachment Item - +### Trace Attachment Item + **Item headers:** | Field | Type | Required | Since | Description | @@ -307,10 +307,10 @@ The trace attachment payload consists of a JSON metadata object immediately foll ## Public API -### Attachment Constructors - +### Attachment Constructors + SDKs **SHOULD** implement two types of attachment constructors: 1. **Path-based** — takes a file path. The SDK reads the file when an event is captured, not when the user adds the attachment to the scope. @@ -329,10 +329,10 @@ Attachments **SHOULD** offer a flag `addToTransactions` that specifies whether t -### Configuration Options - +### Configuration Options + | Option | Type | Default | Since | Description | |--------|------|---------|-------|-------------| | `maxAttachmentSize` | Integer (bytes) | 20 MiB | 1.1.0 | Maximum size of a single attachment. The SDK **MUST** discard items larger than this when converting to envelope items. | diff --git a/develop-docs/sdk/telemetry/check-ins.mdx b/develop-docs/sdk/telemetry/check-ins.mdx index 47d14e0fcf7ee..fbaf2f3acf939 100644 --- a/develop-docs/sdk/telemetry/check-ins.mdx +++ b/develop-docs/sdk/telemetry/check-ins.mdx @@ -88,10 +88,10 @@ SDKs can send monitor configuration (schedule, thresholds, timezone) alongside a ## Behavior -### Check-In Lifecycle - +### Check-In Lifecycle + SDKs **MUST** generate a unique `check_in_id` (UUID v4) when a job execution starts and send a check-in with status `in_progress`. When the job completes, SDKs **MUST** send a second check-in with the same `check_in_id` and status `ok` (success) or `error` (failure). @@ -100,20 +100,20 @@ SDKs **SHOULD** compute the `duration` field for terminal check-ins (`ok` or `er -### Trace Context Linking - +### Trace Context Linking + SDKs **SHOULD** include a `contexts.trace` object with a `trace_id` field to link the check-in to associated errors and traces. If the job execution is part of an active trace, the SDK **SHOULD** use that trace's `trace_id`. Otherwise, the SDK **MAY** generate a new `trace_id` for correlation purposes. -### Updating in_progress Check-Ins - +### Updating in_progress Check-Ins + SDKs **MAY** send a check-in with `check_in_id` set to an empty UUID (128-bit zero value, `00000000000000000000000000000000`) to indicate that Sentry **SHOULD** update the most recent `in_progress` check-in for the given monitor. If no `in_progress` check-in exists, Sentry creates a new one. @@ -122,20 +122,20 @@ This is useful for fire-and-forget patterns where the SDK does not retain the or -### Monitor Upsert - +### Monitor Upsert + SDKs **MAY** include a `monitor_config` object in the check-in payload. When present, Sentry creates the monitor if it does not exist, or updates its configuration if it does. SDKs **SHOULD** only send `monitor_config` on the first check-in of a job execution (the `in_progress` check-in), not on every check-in. -### Auto-Instrumentation - +### Auto-Instrumentation + SDKs **MAY** provide integrations that automatically instrument popular scheduling libraries. When available, these integrations **SHOULD**: 1. Automatically discover scheduled jobs and derive `monitor_slug` values. @@ -150,10 +150,10 @@ Known integrations include Celery Beat (Python), node-cron / cron / node-schedul ## Wire Format -### Check-In Payload - +### Check-In Payload + A check-in is sent as a `check_in` envelope item containing a JSON object. ```json @@ -194,10 +194,10 @@ A check-in is sent as a `check_in` envelope item containing a JSON object. -### Monitor Configuration Payload - +### Monitor Configuration Payload + When included, the `monitor_config` object supports the following fields: ```json @@ -229,10 +229,10 @@ When included, the `monitor_config` object supports the following fields: -### Schedule Configuration - +### Schedule Configuration + This configuration format differs slightly from what is accepted in the monitors frontend APIs. @@ -261,10 +261,10 @@ The `schedule` object **MUST** contain a `type` field set to either `crontab` or ## Public API -### Capture Check-In - +### Capture Check-In + SDKs **MUST** expose a top-level function to send a check-in: ``` @@ -284,10 +284,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Monitor Wrapper - +### Monitor Wrapper + SDKs **SHOULD** expose a higher-level wrapper that automatically sends `in_progress` and `ok`/`error` check-ins around a callback: ``` @@ -308,10 +308,10 @@ SDKs **MAY** additionally provide language-idiomatic alternatives: -### Hooks - +### Hooks + Check-in events **MUST NOT** go through the `beforeSend` hook. The `beforeSend` hook is reserved for error events. SDKs **MAY** implement a dedicated `beforeSendCheckIn` hook that applies only to check-in events. diff --git a/develop-docs/sdk/telemetry/client-reports.mdx b/develop-docs/sdk/telemetry/client-reports.mdx index c723b88d05654..2175f35b9994a 100644 --- a/develop-docs/sdk/telemetry/client-reports.mdx +++ b/develop-docs/sdk/telemetry/client-reports.mdx @@ -129,10 +129,10 @@ Client reports do not expect 100 percent correct numbers, and it is acceptable f -### Network Failure Recording - +### Network Failure Recording + #### Successful Sends (HTTP 2xx) When SDKs receive an `HTTP 2xx` status code response from Sentry, they **MUST** consider it a successful send. No client report is recorded. @@ -257,10 +257,10 @@ There is no expectation that such bookkeeping can work transparently for custom ## Wire Format -### Envelope Item - +### Envelope Item + Item type `"client_report"` contains a client report payload encoded in JSON. **Constraints:** @@ -272,10 +272,10 @@ Item type `"client_report"` contains a client report payload encoded in JSON. -### Payload Structure - +### Payload Structure + A client report consists of a JSON payload with the following fields: | Field | Type | Required | Since | Description | @@ -293,10 +293,10 @@ Each outcome object in `discarded_events` has: -### Discard Reasons - +### Discard Reasons + The following discard reasons are defined for `discarded_events`: | Reason | Since | Description | @@ -320,10 +320,10 @@ In case a reason needs to be added, it also has to be added to the allowlist in -### Relay Outcome Types - +### Relay Outcome Types + The following outcome types are reserved for relay use: `rate_limited_events`, `filtered_events`, `filtered_sampling_events` diff --git a/develop-docs/sdk/telemetry/feedbacks.mdx b/develop-docs/sdk/telemetry/feedbacks.mdx index 4b48119b2f476..8832cde1044ad 100644 --- a/develop-docs/sdk/telemetry/feedbacks.mdx +++ b/develop-docs/sdk/telemetry/feedbacks.mdx @@ -51,10 +51,10 @@ Files of any type (screenshots, logs, documents) can accompany a feedback event ## Behavior -### SDK Pipeline - +### SDK Pipeline + A feedback captured by `capture_feedback` is processed through the SDK pipeline. The feedback event can be discarded at any stage, at which point no further processing happens. SDKs **SHOULD** implement a `beforeSendFeedback` callback to allow users to modify or discard the feedback before it is sent. This callback **SHOULD** be similar to the existing [`beforeSend`](/sdk/foundations/client/hooks/#before-send-hook) callback used for error events. Feedback events **MUST NOT** go through the `beforeSend` hook. @@ -67,18 +67,18 @@ There is no sample rate for feedbacks — they are always sent. However, a feedb -### Session Replay Integration - +### Session Replay Integration + When sending feedback, SDKs **SHOULD** flush the current Session Replay, if running. This ensures a meaningful replay recording exists and can be included in the `replay_id` attribute of the feedback context. -### Replay Sampling Timing for Feedback Widgets - +### Replay Sampling Timing for Feedback Widgets + For feedback widgets specifically, when Session Replay's `onErrorSampleRate` is greater than 0, SDKs **MUST** sample and flush the replay when the widget **opens**, not when the user submits the feedback. This timing is critical because: @@ -89,28 +89,28 @@ This timing is critical because: -### Replay Sampling Timing for Manual API - +### Replay Sampling Timing for Manual API + When feedback is captured using the manual API (`capture_feedback`), SDKs **MUST** sample and flush the replay during the execution of the feedback capture API to ensure session context is preserved. -### User-Facing Platforms - +### User-Facing Platforms + On user-facing platforms such as mobile, desktop, or browser, SDKs **SHOULD** provide first-class support for requesting user feedback when an error or crash occurs. See the user-facing docs for [Apple](https://docs.sentry.io/platforms/apple/enriching-events/user-feedback/) and [Java](https://docs.sentry.io/platforms/java/enriching-events/user-feedback/) for API examples. On mobile and desktop, it is common to prompt the user for feedback after a crash happened on the previous run of the application. SDKs **SHOULD** implement the `onCrashedLastRun` callback on the options. This callback gets called shortly after the initialization of the SDK when the last program execution terminated with a crash. The SDK **SHOULD** execute the callback only once during the entire run of the program to avoid multiple callbacks if there are multiple crash events to send. -### Backend Platforms - +### Backend Platforms + On backend platforms, SDKs **SHOULD** document how to use the [last event ID](/sdk/expected-features/#retrieve-last-event-id) to prompt the user for feedback themselves. @@ -119,10 +119,10 @@ On backend platforms, SDKs **SHOULD** document how to use the [last event ID](/s ## Wire Format -### Feedback Payload - +### Feedback Payload + A feedback is sent as a `feedback` envelope item containing a JSON object. The object is an [event payload](/sdk/foundations/transport/event-payloads/) with an additional `feedback` context object. #### Envelope Item Constraints @@ -165,10 +165,10 @@ The `contexts.feedback` object carries user-provided feedback data: -### File Attachments - +### File Attachments + SDKs **MAY** attach files of any type to a feedback (screenshots, logs, documents, etc.) by sending them as [attachment items](/sdk/telemetry/attachments/), with `event_id` corresponding to the feedback item. SDKs **SHOULD** send attachment items in the same envelope as the feedback item. (since 1.3.0) Attachments are not limited to screenshots — any file type is supported. @@ -177,10 +177,10 @@ SDKs **MAY** attach files of any type to a feedback (screenshots, logs, document ## Public API -### Capture Feedback - +### Capture Feedback + SDKs **MUST** expose a top-level function to send a feedback: ``` diff --git a/develop-docs/sdk/telemetry/logs.mdx b/develop-docs/sdk/telemetry/logs.mdx index fb80f75642722..6bb46e3ef9f72 100644 --- a/develop-docs/sdk/telemetry/logs.mdx +++ b/develop-docs/sdk/telemetry/logs.mdx @@ -73,7 +73,7 @@ There are two wire protocols: the `log` envelope with the Sentry Log protocol (p Related specs: - [Envelopes](/sdk/foundations/transport/envelopes/) — transport format - [Attributes](/sdk/foundations/state-management/scopes/attributes) — attribute type system -- [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance) — required for trace context +- [Tracing without Performance](/sdk/foundations/trace-propagation/#default-propagation) — required for trace context - [Trace Origin](/sdk/telemetry/traces/trace-origin/) — origin attribute format --- @@ -117,10 +117,10 @@ Logs are buffered before sending. SDKs collect logs into a buffer and flush them ## Behavior -### Log Processing Pipeline - +### Log Processing Pipeline + Log processing **MUST** follow this order: 1. Capture log via [Public APIs](#logger-module) (e.g. `Sentry.logger.info`) or via [SDK integrations](#sdk-integrations). @@ -134,16 +134,16 @@ Log processing **MUST** follow this order: -An SDK **SHOULD** implement [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance) before adding support for logs. This is required to ensure logs are associated with traces and that the correct trace context is sent to Sentry. +An SDK **SHOULD** implement [Tracing without Performance](/sdk/foundations/trace-propagation/#default-propagation) before adding support for logs. This is required to ensure logs are associated with traces and that the correct trace context is sent to Sentry. -### Default Attributes - +### Default Attributes + SDKs **MUST** attach the following attributes to every log: | Attribute | Since | Description | @@ -171,10 +171,10 @@ SDKs **SHOULD** minimize default attributes. Logs are charged per byte size. New -### SDK Integration Origin - +### SDK Integration Origin + If a log is generated by an SDK integration, the SDK **SHOULD** set the `sentry.origin` attribute per the [Trace Origin](/sdk/telemetry/traces/trace-origin/) documentation. Since 1.9.0, logs follow these rules: @@ -185,10 +185,10 @@ Since 1.9.0, logs follow these rules: -### User Attributes - +### User Attributes + SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` (since 1.14.0): | Attribute | Description | @@ -199,10 +199,10 @@ SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` -### User Agent Parsing - +### User Agent Parsing + By default, Relay parses the user agent attached to an incoming log envelope to extract `browser` and `os` information. SDKs **MAY** attach these attributes if they do not forward a user agent: | Attribute | Description | @@ -212,10 +212,10 @@ By default, Relay parses the user agent attached to an incoming log envelope to -### Backend SDK Attributes - +### Backend SDK Attributes + Backend SDKs (Node.js, Python, PHP, etc.) **SHOULD** attach: | Attribute | Description | @@ -224,10 +224,10 @@ Backend SDKs (Node.js, Python, PHP, etc.) **SHOULD** attach: -### Mobile, Desktop, and Native SDK Attributes - +### Mobile, Desktop, and Native SDK Attributes + Mobile, desktop, and native SDKs (Android, Apple, Electron, etc.) **SHOULD** attach: | Attribute | Description | @@ -240,10 +240,10 @@ Mobile, desktop, and native SDKs (Android, Apple, Electron, etc.) **SHOULD** att -### Buffering - +### Buffering + SDKs **MUST** buffer logs before sending. A simple initial strategy is flushing when the buffer exceeds 100 items or 5 seconds have passed. The buffer **SHOULD** forward logs to the transport in the scenarios outlined in the [telemetry buffer data forwarding scenarios](/sdk/foundations/processing/telemetry-processor/#data-forwarding-scenarios). SDKs **MUST NOT** send more than 100 logs per envelope (since 1.15.0). Relay is optimized for this limit. @@ -254,54 +254,54 @@ SDKs **MUST NOT** release logging capabilities to users without a buffering impl -### Data Category and Rate Limiting - +### Data Category and Rate Limiting + Logs use the `log_item` data category for rate limiting in Relay. Both `log` and `otel_log` envelopes are covered by this data category. SDKs **MUST** implement this data category. Rate limiting applies as usual with no special behavior for logs. SDKs **MUST** track client outcomes for this data category to report how often logs are dropped. -### SDK Integrations - +### SDK Integrations + SDKs **SHOULD** provide integrations that capture logs from platform logging libraries (e.g., JavaScript's `console`, Python's `logging`, Java's `Log4j`) when `enableLogs`/`enable_logs` is set to `true`. SDKs **MAY** introduce additional options beyond `enableLogs`/`enable_logs` to gate integration-specific functionality (e.g., controlling log appenders added via external config). -### Tracing Association - +### Tracing Association + Logs **SHOULD** be associated with traces. If a log is recorded during an active span, SDKs **SHOULD** set the `span_id` property to the active span's ID. -### Replay Association - +### Replay Association + Logs **SHOULD** be associated with replays. If a log is recorded during an active replay, SDKs **SHOULD** set the `sentry.replay_id` attribute to the active replay's ID. -### Debug Mode - +### Debug Mode + If `debug` is set to `true` in SDK init, calls to the Sentry logger API **SHOULD** also print to the console with the appropriate log level. This aids debugging of logging setups. -### Client Reports - +### Client Reports + SDKs **MUST** report count (`log_item`) and size in bytes (`log_byte`) of discarded log messages. An approximation of log size is sufficient (e.g., by counting as if serialized). @@ -310,10 +310,10 @@ SDKs **MUST** report count (`log_item`) and size in bytes (`log_byte`) of discar ## Wire Format -### `log` Envelope Item - +### `log` Envelope Item + The `log` envelope item contains an array of log payloads encoded as JSON, allowing multiple logs per envelope item. An envelope **MUST** contain at most one `log` envelope item — all log entries for a flush are batched into a single item's `items` array. Logs from different traces **MAY** be mixed into the same `log` item, but if they are, the envelope **MUST NOT** include a DSC (dynamic sampling context) header. @@ -339,10 +339,10 @@ An envelope **MUST** contain at most one `log` envelope item — all log entries -### `log` Envelope Item Payload - +### `log` Envelope Item Payload + Each log in the `items` array is a JSON object: ```json @@ -378,10 +378,10 @@ Each log in the `items` array is a JSON object: -### `otel_log` Envelope Item Payload - +### `otel_log` Envelope Item Payload + The `otel_log` envelope item payload is a JSON object implementing the [OpenTelemetry Log Data Model](https://opentelemetry.io/docs/specs/otel/logs/data-model/). Multiple `otel_log` items **MAY** be sent per envelope. @@ -425,10 +425,10 @@ The `otel_log` envelope item payload is a JSON object implementing the [OpenTele ## Public API -### Initialization Options - +### Initialization Options + SDKs **MUST** expose the following configuration options: | Option | Type | Default | Since | Description | @@ -446,10 +446,10 @@ Sentry.init({ -### Logger Module - +### Logger Module + SDKs **MUST** expose logging methods in a `logger` module or namespace, with one method per [severity level](#severity-levels): - `Sentry.logger.trace` @@ -467,10 +467,10 @@ SDKs **MAY** add additional helpers (e.g., decorators, string template helpers) -### Threading and Concurrency - +### Threading and Concurrency + The `Sentry.logger.X` methods are fire-and-forget (no return value). SDKs **MAY** run these methods on a separate thread or queue them for later processing, including evaluating the string template and running internal hooks like `beforeSendLog`. SDKs **MUST** ensure logs are sent in the order they are received. diff --git a/develop-docs/sdk/telemetry/metrics.mdx b/develop-docs/sdk/telemetry/metrics.mdx index 65957adea3cb1..30664770f81d3 100644 --- a/develop-docs/sdk/telemetry/metrics.mdx +++ b/develop-docs/sdk/telemetry/metrics.mdx @@ -56,7 +56,7 @@ The envelope item type is named `trace_metric` for internal usage to avoid namin Related specs: - [Envelopes](/sdk/foundations/transport/envelopes/) — transport format - [Attributes](/sdk/foundations/state-management/scopes/attributes) — attribute types and structure -- [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance/) — required before adding metrics support +- [Tracing without Performance](/sdk/foundations/trace-propagation/#default-propagation) — required before adding metrics support - [Telemetry Processor](/sdk/foundations/processing/telemetry-processor/) — buffer data forwarding scenarios --- @@ -85,14 +85,14 @@ Multiple metrics are batched into a single `trace_metric` envelope item for effi -An SDK **SHOULD** implement [Tracing without Performance](/sdk/telemetry/traces/tracing-without-performance/) before adding support for metrics. This is required to ensure that metrics are associated with traces and that the correct trace context is sent to Sentry. +An SDK **SHOULD** implement [Tracing without Performance](/sdk/foundations/trace-propagation/#default-propagation) before adding support for metrics. This is required to ensure that metrics are associated with traces and that the correct trace context is sent to Sentry. -### Processing Pipeline - +### Processing Pipeline + Metric processing **MUST** follow this order: 1. Capture metric via [Public APIs](#metrics-module) (e.g. `Sentry.metrics.count`). @@ -104,10 +104,10 @@ Metric processing **MUST** follow this order: -### Default Attributes - +### Default Attributes + SDKs **MUST** attach the following attributes to every metric by default: 1. `sentry.environment` — the environment set in the SDK, if defined. @@ -119,10 +119,10 @@ SDKs **SHOULD** minimize the number of default attributes. Metrics cardinality c -### User Attributes - +### User Attributes + SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` ([unless manually set by user](/sdk/expected-features/data-handling/#sensitive-data), since 2.5.0): 1. `user.id` — the user ID. Maps to `id` in the [User](/sdk/foundations/transport/event-payloads/user/) payload. @@ -131,10 +131,10 @@ SDKs **MAY** attach user information as attributes, guarded by `sendDefaultPii` -### Browser Attributes (Relay) - +### Browser Attributes (Relay) + By default, Relay parses the user agent attached to an incoming metric envelope to extract `browser` and `os` information. These attributes are attached by Relay, but client-side SDKs **MAY** attach them if they do not forward a user agent when sending metrics to Sentry. 1. `browser.name` — display name of the browser application. Maps to `name` in the [Browser Context](/sdk/foundations/transport/event-payloads/contexts/#browser-context). @@ -142,20 +142,20 @@ By default, Relay parses the user agent attached to an incoming metric envelope -### Backend SDK Attributes - +### Backend SDK Attributes + Backend SDKs (Node.js, Python, PHP, etc.) **SHOULD** attach the following attribute: 1. `server.address` — the address of the server that sent the metric. Equivalent to [`server_name`](/sdk/foundations/transport/event-payloads/#optional-attributes) attached to errors and transactions. -### Buffering - +### Buffering + SDKs **MUST** buffer metrics before sending them (since 2.2.0, tightened from SHOULD). SDKs **SHOULD** flush the buffer when specific conditions are met. For initial implementation, a simple strategy is fine, for example: flushing if the buffer length exceeds 100 items or if 5 seconds have passed. To prevent data loss, the buffer **SHOULD** forward metrics to the transport in the scenarios outlined in the [telemetry buffer data forwarding scenarios](/sdk/foundations/processing/telemetry-processor/#data-forwarding-scenarios) (since 2.2.0). @@ -166,20 +166,20 @@ Furthermore: -### Tracing Association - +### Tracing Association + Metrics **SHOULD** be associated with traces if possible. If a metric is recorded during an active span, the SDK **SHOULD** set the `span_id` property of the metric to the span ID of the span that was active when the metric was collected. The `trace_id` field is **REQUIRED** on every metric payload and **MUST** be taken from the current propagation context. -### Replay Association - +### Replay Association + Whenever possible, metrics **SHOULD** be linked to replays. If a metric is recorded while an active, sampled replay is in progress, the SDK **SHOULD** attach: 1. `sentry.replay_id` — the ID of the replay that was active when the metric was collected. This **MUST NOT** be set if there was no active replay. @@ -187,18 +187,18 @@ Whenever possible, metrics **SHOULD** be linked to replays. If a metric is recor -### Data Category and Rate Limiting - +### Data Category and Rate Limiting + The data category for metrics is `trace_metric`. Rate limiting applies as usual. SDKs **SHOULD** track client outcomes to monitor how often metrics are dropped. If the SDK receives a rate limit, it **MUST NOT** send any trace metrics until the limit expires (based on the communicated end timestamp). -### Debug Logging - +### Debug Logging + If `debug` is set to `true` in SDK init, calls to the Sentry metrics API **SHOULD** also print to the console with appropriate details. This will help debugging metrics setups. @@ -207,10 +207,10 @@ If `debug` is set to `true` in SDK init, calls to the Sentry metrics API **SHOUL ## Wire Format -### `trace_metric` Envelope Item - +### `trace_metric` Envelope Item + Metrics are sent as a `trace_metric` envelope item containing a JSON object with an `items` array. See the [Examples](#full-trace_metric-envelope) section for a complete envelope. An envelope **MUST** contain at most one `trace_metric` envelope item — all metrics for a flush are batched into a single item's `items` array. Metrics from different traces **MAY** be mixed into the same `trace_metric` item, but if they are, the envelope **MUST NOT** include a DSC (dynamic sampling context) header. @@ -236,10 +236,10 @@ An envelope **MUST** contain at most one `trace_metric` envelope item — all me -### Metric Payload - +### Metric Payload + Each metric in the `items` array is a JSON object with the following fields: ```json @@ -276,10 +276,10 @@ Each metric in the `items` array is a JSON object with the following fields: ## Public API -### Initialization Options - +### Initialization Options + SDKs **MUST** expose the following configuration options: - `enableMetrics`/`enable_metrics` — a boolean flag to control if metric envelopes will be generated and sent to Sentry. If `false`, the SDK **MUST NOT** send metrics. Defaults to `true`. @@ -300,10 +300,10 @@ Sentry.init({ -### Metrics Module - +### Metrics Module + SDKs **MUST** expose metrics methods in a `metrics` module or namespace. At minimum, the SDK **MUST** implement the following methods: - `Sentry.metrics.count(name, value, options)` — increment a counter diff --git a/develop-docs/sdk/telemetry/profiles/index.mdx b/develop-docs/sdk/telemetry/profiles/index.mdx index 16d8ba5065a0b..83e3330f95b3d 100644 --- a/develop-docs/sdk/telemetry/profiles/index.mdx +++ b/develop-docs/sdk/telemetry/profiles/index.mdx @@ -95,20 +95,20 @@ Continuous profiling operates in one of two lifecycle modes: ## Behavior -### Sampling Frequency - +### Sampling Frequency + SDKs **SHOULD** collect profile samples at a frequency of 101Hz (roughly once every 10 milliseconds). The 101Hz value is intentional to avoid [lockstep sampling](https://stackoverflow.com/a/45471031/1181370) — a condition where profiling samples occur at the same frequency as a loop in the application. (since 2.1.1) 101 was chosen for its primality; 99 (1 below 100) is evenly divisible by several smaller numbers, which could lead to similar lockstep behavior. -### Profile Lifecycle Modes - +### Profile Lifecycle Modes + SDKs implementing continuous profiling **MUST** support two lifecycle modes: **Manual mode** (`profile_lifecycle: 'manual'`): @@ -126,10 +126,10 @@ SDKs implementing continuous profiling **MUST** support two lifecycle modes: -### Tracing Context Linking - +### Tracing Context Linking + For continuous profiling (V2), additional context **MUST** be attached to transaction and span payloads to link them to profile data. **Profile context** (`.contexts.profile`): @@ -147,10 +147,10 @@ SDKs **MUST** include `thread.id` in span data. `thread.name` and `profiler_id` ## Wire Format -### V1 Sample Format Payload - +### V1 Sample Format Payload + A V1 profile **MUST** be associated with a transaction and sent in the same envelope. #### V1 Metadata Fields @@ -183,10 +183,10 @@ A V1 profile **MUST** be associated with a transaction and sent in the same enve -### V2 Sample Format Payload - +### V2 Sample Format Payload + A V2 profile chunk exists independently and is sent as a `profile_chunk` envelope item. #### V2 Metadata Fields @@ -206,10 +206,10 @@ A V2 profile chunk exists independently and is sent as a `profile_chunk` envelop -### Profile Data - +### Profile Data + Both V1 and V2 formats share the same `profile` object structure: | Field | Type | Required | Since | Description | @@ -231,10 +231,10 @@ Accepted measurement units: `nanosecond`, `ns`, `hertz`, `hz`, `byte`, `percent` -### V1 Validation - +### V1 Validation + Relay rejects a V1 profile if any of these conditions are true: - Profile data is missing (no frames, no samples, no stacks) - Fewer than 2 samples @@ -249,10 +249,10 @@ SDKs **SHOULD** remove unnecessary data like thread entries without samples from -### V2 Validation - +### V2 Validation + Relay rejects a V2 profile chunk if any of these conditions are true: - Chunk data is missing (no frames, no samples, no stacks) - Required metadata is missing @@ -264,10 +264,10 @@ SDKs **SHOULD** remove unnecessary data like thread entries without samples from -### V1 Envelope Format - +### V1 Envelope Format + A V1 profile **MUST** be serialized as JSON and sent in the same [envelope](/sdk/foundations/transport/envelopes/) as the associated transaction with item type `profile`. An envelope **MUST** contain at most one `profile` item. ```json @@ -280,10 +280,10 @@ A V1 profile **MUST** be serialized as JSON and sent in the same [envelope](/sdk -### V2 Envelope Format - +### V2 Envelope Format + A V2 profile chunk **MUST** be serialized as JSON and sent in an [envelope](/sdk/foundations/transport/envelopes/) with item type `profile_chunk`. (since 2.4.0) The `platform` item header is **REQUIRED** for rate limiting and categorization and **MUST** match the `platform` field in the payload. @@ -296,10 +296,10 @@ A V2 profile chunk **MUST** be serialized as JSON and sent in an [envelope](/sdk -### Tracing Context Payload - +### Tracing Context Payload + For V2 continuous profiling, SDKs **MUST** modify transaction and span payloads to enable profile linking. **Profile context** (`.contexts.profile`): @@ -329,10 +329,10 @@ For V2 continuous profiling, SDKs **MUST** modify transaction and span payloads ## Public API -### Profile Session Sample Rate - +### Profile Session Sample Rate + SDKs implementing continuous profiling **MUST** accept a `profileSessionSampleRate` configuration option (number, 0.0–1.0, default 0). The sampling decision is made once when the SDK is initialized. The definition of a profiling session depends on the profiling type: @@ -348,10 +348,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Profile Lifecycle - +### Profile Lifecycle + SDKs implementing continuous profiling **MUST** accept a `profileLifecycle` configuration option with values `'trace'` or `'manual'` (default: `'manual'`). See [Profile Lifecycle Modes](#profile-lifecycle-modes) for behavior details. @@ -362,10 +362,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Start Profiler on App Start - +### Start Profiler on App Start + Mobile SDKs **MAY** accept a `startProfilerOnAppStart` configuration option (boolean, default `false`). When `true`, profiling starts as early as possible during app startup, before `startProfiler()` can be manually called. The `profileSessionSampleRate` for app start profiling is evaluated on the **previous** app launch and applied on the **next** launch, since the sample rate cannot be evaluated at launch time. @@ -379,10 +379,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Start Profiler - +### Start Profiler + SDKs implementing continuous profiling **SHOULD** expose a function to start the profiler: ``` @@ -402,10 +402,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Stop Profiler - +### Stop Profiler + SDKs implementing continuous profiling **SHOULD** expose a function to stop the profiler: ``` diff --git a/develop-docs/sdk/telemetry/replays.mdx b/develop-docs/sdk/telemetry/replays.mdx index 4e35935d18ee5..9089285567315 100644 --- a/develop-docs/sdk/telemetry/replays.mdx +++ b/develop-docs/sdk/telemetry/replays.mdx @@ -54,10 +54,10 @@ A replay is composed of **segments**, each identified by a `segment_id` (startin ## Behavior -### Session Mode - +### Session Mode + When an SDK records Session Replay in `session` mode (`sessionSampleRate` is specified), the recording **SHOULD** start when the SDK is initialized and **MUST** be continuously streamed to the Sentry servers. SDKs **SHOULD** send a replay envelope every 5 seconds. The maximum duration of the recording **MUST NOT** exceed 60 minutes (or 15 minutes without activity on Web). (since 1.2.0) After the hard limit has been reached, the SDK **MUST** stop recording, clear the current `replay_id`, and remove it from the Scope so all subsequent events are not associated with it. @@ -66,10 +66,10 @@ For SDKs that support disk cache, the recording **SHOULD** pause when there is n -### Buffer Mode - +### Buffer Mode + When an SDK records Session Replay in `buffer` mode (`onErrorSampleRate` is specified), the recording **SHOULD** start when the SDK is initialized and **MUST** be buffered in-memory (and to disk if the SDK supports disk cache) in a ring buffer for up to 30 seconds back. Capturing of the recording **MAY** be triggered when one of the following conditions is met: @@ -87,10 +87,10 @@ If the crash or error event has been dropped in `beforeSend`, the replay **MUST ## Wire Format -### Replay Event Payload - +### Replay Event Payload + A `replay_event` envelope item **MUST** always be sent together with a `replay_recording` item in the same envelope. An envelope **MUST** contain at most one `replay_event` item. #### Replay Attributes @@ -129,10 +129,10 @@ The following attributes are a subset of the [optional attributes](/sdk/foundati -### Replay Recording Item - +### Replay Recording Item + An envelope **MUST** contain at most one `replay_recording` item. The `length` item header is **REQUIRED** and specifies the size of the recording payload. The `replay_recording` item consists of two sub-items delimited by a newline: @@ -151,10 +151,10 @@ The `replay_recording` item consists of two sub-items delimited by a newline: ## Public API -### Session Sample Rate - +### Session Sample Rate + SDKs **MUST** accept a `replaysSessionSampleRate` configuration option (number, 0.0–1.0, default 0). This controls the fraction of sessions recorded in session mode. `1.0` records all sessions, `0` records none. Naming **SHOULD** follow the SDK's language conventions: @@ -163,10 +163,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Error Sample Rate - +### Error Sample Rate + SDKs **MUST** accept a `replaysOnErrorSampleRate` configuration option (number, 0.0–1.0, default 0). This controls the fraction of sessions buffered for error replay. `1.0` captures all sessions with an error, `0` captures none. Naming **SHOULD** follow the SDK's language conventions: @@ -175,10 +175,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Replay Integration - +### Replay Integration + SDKs **MUST** provide a replay integration that initializes the recording subsystem: ``` @@ -194,10 +194,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Get Replay Instance - +### Get Replay Instance + SDKs **SHOULD** expose a function to retrieve the active replay instance: ``` @@ -208,10 +208,10 @@ Returns the replay integration instance if replay is initialized, or `null` if n -### Get Replay ID - +### Get Replay ID + The replay instance **MUST** expose a method to retrieve the current replay identifier: ``` @@ -222,10 +222,10 @@ Returns the current `replay_id` (string) if a replay is active, or `null` if no -### Start - +### Start + The replay instance **SHOULD** expose a method to manually start recording in session mode: ``` @@ -236,10 +236,10 @@ Starts recording in session mode regardless of sample rates. If a session is alr -### Start Buffering - +### Start Buffering + The replay instance **SHOULD** expose a method to manually start recording in buffer mode: ``` @@ -250,10 +250,10 @@ Starts recording in buffer mode regardless of sample rates. If a session is alre -### Stop - +### Stop + The replay instance **SHOULD** expose a method to stop recording: ``` @@ -264,10 +264,10 @@ Flushes any pending recording data, stops the replay, and ends the session. -### Flush - +### Flush + The replay instance **SHOULD** expose a method to flush pending recording data: ``` diff --git a/develop-docs/sdk/telemetry/sessions/index.mdx b/develop-docs/sdk/telemetry/sessions/index.mdx index 67ba698bd8603..6dad570c5cf12 100644 --- a/develop-docs/sdk/telemetry/sessions/index.mdx +++ b/develop-docs/sdk/telemetry/sessions/index.mdx @@ -94,10 +94,10 @@ Sentry's session system uses hourly buckets of pre-materialized data. Session up ## Behavior -### Session Lifecycle - +### Session Lifecycle + Sessions are entirely client-driven. The client determines when a session starts, ends, or transitions to an unhealthy state. - Sessions are updated through session change events that hold the **entire** session state. The most recent event holds the authoritative state. @@ -107,18 +107,18 @@ Sessions are entirely client-driven. The client determines when a session starts -### Attribute Immutability - +### Attribute Immutability + SDKs **MUST NOT** change session attributes (`did`, `started`, or any `attrs` fields) in subsequent updates. Only `status`, `duration`, and `errors` **MAY** change. If a user is not known at session start, the session start **SHOULD** be delayed or the session restarted once the user is known. -### Terminal Session States - +### Terminal Session States + Once a session reaches a terminal state, the SDK **MUST NOT** send further updates. Terminal states are: `exited`, `crashed`, `abnormal`, and (since 1.6.0) `unhandled`. SDKs **SHOULD** distinguish between terminal states: @@ -137,10 +137,10 @@ SDKs **SHOULD** distinguish between terminal states: -### Error Counting - +### Error Counting + SDKs **MUST** maintain a running `errors` counter that is incremented when errors occur during the session. The counter **MUST** also be incremented when a session goes to `crashed` (the crash itself is always an error). Ingest forces `errors` to 1 if not set or 0. A session that is `ok` with `errors > 0` is considered "errored." All `crashed` and `abnormal` sessions are also considered errored but are subtracted from the final errored count. @@ -161,10 +161,10 @@ A session that is `ok` with `errors > 0` is considered "errored." All `crashed` -### Session Modes - +### Session Modes + SDKs **SHOULD** default to the session mode most appropriate for the language ecosystem: **User-mode** _(application-mode)_: @@ -185,10 +185,10 @@ When using user-mode, a single session **SHOULD** start at application initializ -### Pre-aggregation - +### Pre-aggregation + Server-mode SDKs **SHOULD** pre-aggregate closed sessions before sending to Sentry. When a session closes and has not been sent upstream (its `init` flag would be `true`), it is eligible for aggregation: 1. Round the `started` timestamp down to the minute. @@ -199,10 +199,10 @@ Server-mode SDKs **SHOULD** pre-aggregate closed sessions before sending to Sent -### Session Update Filtering - +### Session Update Filtering + When events are dropped by filtering mechanisms (sample rate, rate limiting, `beforeSend`, event processors, or ignored exception types), the session update behavior depends on the drop reason: - Events dropped due to **sampling** or **rate limiting** **SHOULD** still update the session — the event was dropped to save quota but represents something the developer cares about. @@ -222,10 +222,10 @@ If the event has been dropped but the session was updated, the session update ** -### Session Updates and Sending - +### Session Updates and Sending + SDKs **SHOULD** automatically update the current session whenever data is captured (at the same point where `apply_to_scope` is called) to increment the `errors` count or update the session based on the distinct ID. SDKs **SHOULD** aim to minimize the number of envelopes sent upstream. @@ -242,10 +242,10 @@ SDKs **SHOULD** send session updates in the same envelope as crash events when t ## Wire Format -### Session Update Payload - +### Session Update Payload + A session update is sent as a `session` envelope item containing a JSON object. Multiple `session` envelope items **MAY** appear in a single envelope. Ingestion may limit the maximum number of items per envelope. | Field | Type | Required | Since | Description | @@ -273,10 +273,10 @@ A session update is sent as a `session` envelope item containing a JSON object. -### Session Aggregates Payload - +### Session Aggregates Payload + For server-mode sessions, SDKs **SHOULD** send aggregated session counts as a `sessions` envelope item. Multiple `sessions` envelope items **MAY** appear in a single envelope. Ingestion may limit the maximum number of items per envelope. | Field | Type | Required | Since | Description | @@ -302,10 +302,10 @@ For server-mode sessions, SDKs **SHOULD** send aggregated session counts as a `s ## Public API -### Start Session - +### Start Session + SDKs **MUST** expose a function to start a session: ``` @@ -322,10 +322,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### End Session - +### End Session + SDKs **MUST** expose a function to end a session: ``` @@ -340,10 +340,10 @@ Naming **SHOULD** follow the SDK's language conventions: -### Auto Session Tracking - +### Auto Session Tracking + SDKs **SHOULD** accept an `autoSessionTracking` configuration option (boolean, default varies by SDK). When enabled, the SDK automatically starts and ends sessions based on the session mode. SDKs **MAY** also expose `startAutoSessionTracking()` / `stopAutoSessionTracking()` for runtime control. @@ -398,7 +398,8 @@ Naming **SHOULD** follow the SDK's language conventions: } ``` -### Full Envelope (Individual Session) +### Full Envelope +#### Single Session ``` {} @@ -406,7 +407,7 @@ Naming **SHOULD** follow the SDK's language conventions: {"sid":"7c7b6585-f901-4351-bf8d-02711b721929","init":true,"started":"2020-02-07T14:16:00Z","status":"ok","attrs":{"release":"my-project-name@1.0.0"}} ``` -### Full Envelope (Aggregated Sessions) +#### Aggregated Sessions ``` {} diff --git a/develop-docs/sdk/telemetry/spans/span-buffer.mdx b/develop-docs/sdk/telemetry/spans/span-buffer.mdx index b72b169f8d4c9..94a31923fd07d 100644 --- a/develop-docs/sdk/telemetry/spans/span-buffer.mdx +++ b/develop-docs/sdk/telemetry/spans/span-buffer.mdx @@ -47,7 +47,7 @@ Requirements for buckets per trace ID: ### Serialization and Dynamic Sampling Context (DSC) -To ensure the best [Dynamic Sampling Context](/sdk/telemetry/traces/dynamic-sampling-context/) (DSC) consistency, SDKs **SHOULD** materialize and freeze the DSC as late as possible. In practice: +To ensure the best [Dynamic Sampling Context](/sdk/foundations/trace-propagation/dynamic-sampling-context/) (DSC) consistency, SDKs **SHOULD** materialize and freeze the DSC as late as possible. In practice: - The span buffer **SHOULD** enqueue spans but only create the final envelope at **flush time**, not at enqueue time. - At flush time, the span buffer **SHOULD** materialize and freeze the DSC on the segment span if not already done. That way the `trace` envelope header (e.g. for transaction names in the DSC) reflects the latest data. diff --git a/develop-docs/sdk/telemetry/spans/span-trace-propagation.mdx b/develop-docs/sdk/telemetry/spans/span-trace-propagation.mdx deleted file mode 100644 index 82664b003bf91..0000000000000 --- a/develop-docs/sdk/telemetry/spans/span-trace-propagation.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Span Trace Propagation ---- - - - 🚧 This document is work in progress. - - - - This document uses key words such as "MUST", "SHOULD", and "MAY" as defined in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) to indicate requirement levels. - - -## Continue an incoming trace - -To continue a trace from an upstream service, the SDK must expose a method to extract the traceparent and baggage information and apply these to the applicable scope. The method MUST NOT create a new segment span on its own. - -```js -Sentry.continueTrace({ - sentryTrace: request.headers['sentry-trace'], - baggage: request.headers['baggage'], -}, () => { - Sentry.startSpan({ name: 'test' }, () => { - // .... - }); -}) -``` - -```python -sentry_sdk.continue_trace(request.headers) - -with sentry_sdk.start_span(name="test"): - ... -``` - -Newly created root spans should now contain these properties, such as `trace_id` and `parent_span_id`. - -The exact function signature of the `continueTrace` function depends on what's canonical in your SDK. It MAY require explicitly passing `sentry-trace` and `baggage`, or it MAY allow providing a dictionary of headers/environment variables. - -## Continue an outgoing trace - -To propagate a trace to a downstream service, the SDK MUST expose methods to fetch the required information to allow the next service to continue the trace. - -```js -const traceData = Sentry.getTraceData() -``` - -```python -traceparent = sentry_sdk.get_traceparent() -baggage = sentry_sdk.get_baggage() -``` - -## Starting a new trace - -The SDK MUST offer a method to clear trace propagation data, allowing to create spans with a fresh new trace. - -```js -Sentry.startNewTrace(() => { - Sentry.startSpan({ name: 'segment under trace 1' }, () => {...}); -}) - -Sentry.startNewTrace(() => { - Sentry.startSpan({ name: 'segment under trace 2' }, () => {...}); -}) -``` - -```python -import sentry_sdk - -with sentry_sdk.start_span(name="segment under trace 1"): - ... - -sentry_sdk.new_trace() - -# The next span started after new_trace() will NOT continue the same trace: -with sentry_sdk.start_span(name="segment under trace 2"): - ... -``` diff --git a/develop-docs/sdk/telemetry/traces/distributed-tracing/index.mdx b/develop-docs/sdk/telemetry/traces/distributed-tracing/index.mdx deleted file mode 100644 index 76ef277c087c5..0000000000000 --- a/develop-docs/sdk/telemetry/traces/distributed-tracing/index.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Distributed Tracing ---- - -This document describes how an SDK should propagate information between different services to connect all telemetry (errors, profiles, replays, transaction, check-ins, ...) from those services into one trace. - -For an overview see [Distributed Tracing](https://docs.sentry.io/product/performance/distributed-tracing/) in the product docs. - -Sentry uses three containers to hold trace information [`sentry-trace`](/sdk/performance/#header-sentry-trace), [`baggage`](/sdk/performance/dynamic-sampling-context/#baggage-header) and optionally [`traceparent`](/sdk/performance/distributed-tracing/#w3c-trace-context-header). - -With these containers you can propagate a trace to a down-stream service by either: -- adding `sentry-trace` and `baggage` HTTP headers (when making outgoing HTTP requests), -- adding `sentry-trace` and `baggage` as meta data (when putting tasks into a queue, details are specific to the queue you want to support), or -- setting environment variables (when calling another process). In this case the env variables should be called `SENTRY_TRACE` and `SENTRY_BAGGAGE`. - -The SDK running in the receiving service needs to make sure to pick up incoming trace information by -- reading `sentry-trace` and `baggage` headers for each incoming HTTP request, -- reading `sentry-trace` and `baggage` meta data when retrieving an item from a queue, or -- reading the environment variables `SENTRY_TRACE` and `SENTRY_BAGGAGE` on startup. - -This trace information should be stored in the "propagation context" of the current scope. This makes sure that all telemetry that is emitted from the receiving service to Sentry will include the correct trace information. - -## W3C Trace Context Header - -To interoperate with OpenTelemetry (OTel) services, SDKs can optionally send the W3C Trace Context `traceparent` HTTP header on outgoing requests in addition to Sentry’s own `sentry-trace` and `baggage`. This enables traces originating from a Sentry SDK to be continued by components that only use OTel/W3C propagation. - -The `traceparent` header must only be sent when [`propagateTraceparent`](/sdk/telemetry/traces/#propagatetraceparent) is `true` and the request matches `tracePropagationTargets` (same condition as for `sentry-trace`/`baggage`). - -The full spec is available in the [W3C Trace Context](https://www.w3.org/TR/trace-context/) document. diff --git a/develop-docs/sdk/telemetry/traces/index.mdx b/develop-docs/sdk/telemetry/traces/index.mdx index 262ed9bab3412..9861b4d622c0f 100644 --- a/develop-docs/sdk/telemetry/traces/index.mdx +++ b/develop-docs/sdk/telemetry/traces/index.mdx @@ -46,62 +46,11 @@ See more about how sampling should be performed [below](#sampling). ### `tracePropagationTargets` -Sentry SDKs propagate trace information to downstream SDKs via headers on outgoing HTTP requests. The `tracePropagationTargets` option gives users a mechanism of controlling to which outgoing HTTP requests these headers should be attached. For example, users can specify this property to keep trace propagation within their infrastructure, thereby preventing data within the headers from being sent to third party services. - -This option takes an array of strings and/or regular expressions. SDKs should only add trace headers to an outgoing request if the request's URL matches the regex or, in the case of string literals, contains at least one of the items from the array. String literals do not have to be full matches, meaning the URL of a request is matched when it contains a string provided through the option. - -SDKs may choose a default value which makes sense for their use case. Most SDKs default to the regex `.*` (meaning they attach headers to all outgoing requests), but deviation is allowed if necessary. For example, because of CORS, browser-based SDKs default to only adding headers to domain-internal requests. - -See [`sentry-trace`](#header-sentry-trace) and [`baggage`](/sdk/performance/dynamic-sampling-context/#baggage-header) for more details on the individual headers which are attached to outgoing requests. - -#### Example - -The following example shows which URLs of outgoing requests would (not) match a given `tracePropagationTargets` array: - -```JS -// Entries can be strings or regex -tracePropagationTargets: ['localhost', /^\// ,/myApi.com\/v[2-4]/] - -URLs matching: 'localhost:8443/api/users', 'mylocalhost:8080/api/users', '/api/envelopes', 'myApi.com/v2/projects' -URLs not matching: 'someHost.com/data', 'myApi.com/v1/projects' -``` - - - -This Option replaces the non-standardized `tracingOrigins` option which was previously used in some SDKs. SDKs that support `tracingOrigins` are encouraged to deprecate and and eventually remove `tracingOrigins` in favour `tracePropagationTargets`. In case both options are specified by users, SDKs should only rely on the `tracePropagationTargets` array. - - +See [Trace Propagation: tracePropagationTargets](/sdk/foundations/trace-propagation/#trace-propagation-targets). ### `strictTraceContinuation` -This must be a boolean value. Default is `false`. This option controls trace continuation from unknown 3rd party services that happen to be instrumented by a Sentry SDK. - -If the SDK is able parse an org ID from the configured DSN, it must be propagated as a baggage entry with the key `sentry-org_id`. Given a DSN of `https://1234@o1.ingest.us.sentry.io/1`, the org ID is `1`, based on `o1`. - -Additionally, the SDK must be configurable with an optional `orgId: ` setting that takes precedence over the parsed value from the DSN. This option should be set when running a self-hosted version of Sentry or if a non-standard Sentry DSN is used, such as when using a local Relay. - -On incoming traces, the SDK must compare the `sentry-org_id` baggage value against its own parsed value from the DSN or org setting. Only if both match, the trace is continued. If there is no match, neither the trace ID, the parent sampling decision nor the baggage should be taken into account. -The SDK should behave like it is the head of trace in this case, and not consider any propagted values. - -This behavior can be disabled by setting `strictTraceContinuation: false` in the SDK init call. -Initially, SDKs must introduce the this option with a default value of `false`. -Once the majority of SDKs have introduced this option, we'll change the default value to `true` (in a major version bump), making it opt-out. - -Regardless of `strictTraceContinuation` being set to `true` or `false`, if the SDK is either configured with a `org` or was able to parse the value from the DSN, incoming traces containing an `org` value in the baggage that does not match the one from the receiving SDK, the trace is not continuned. - -Examples: - -- baggage: `sentry-org: 1`, SDK config: `org: 1, strictTraceContinuation: false` -> continue trace -- baggage: `sentry-org: none`, SDK config: `org: 1, strictTraceContinuation: false` -> continue trace -- baggage: `sentry-org: 1`, SDK config: `org: none, strictTraceContinuation: false` -> continue trace -- baggage: `sentry-org: none`, SDK config: `org: none, strictTraceContinuation: false` -> continue trace -- baggage: `sentry-org: 1`, SDK config: `org: 2, strictTraceContinuation: false` -> start new trace - -- baggage: `sentry-org: 1`, SDK config: `org: 1, strictTraceContinuation: true` -> continue trace -- baggage: `sentry-org: none`, SDK config: `org: 1, strictTraceContinuation: true` -> start new trace -- baggage: `sentry-org: 1`, SDK config: `org: none, strictTraceContinuation: true` -> start new trace -- baggage: `sentry-org: none`, SDK config: `org: none, strictTraceContinuation: true` -> continue trace -- baggage: `sentry-org: 1`, SDK config: `org: 2, strictTraceContinuation: true` -> start new trace +See [Trace Propagation: strictTraceContinuation](/sdk/foundations/trace-propagation/#strict-trace-continuation). ### `traceOptionsRequests` @@ -118,15 +67,7 @@ The `maxSpans` limit may also help avoiding transactions that never finish (in p ### `propagateTraceparent` -This must be a boolean value. The default is `false`. This option is used to enable the propagation of the W3C Trace Context HTTP header `traceparent` on outgoing HTTP requests. This is useful when the receiving services only support OTel/W3C propagation. - -The `traceparent` header is only sent when `propagateTraceparent` is `true` and the request matches `tracePropagationTargets` (same condition as for `sentry-trace`/`baggage`). - -Header Format: -- Key: `traceparent` -- Value: `00---` where `` is `01` if sampled, otherwise `00`. - -The full spec is available in the [W3C Trace Context](https://www.w3.org/TR/trace-context/) specification. +See [Trace Propagation: propagateTraceparent](/sdk/foundations/trace-propagation/#propagate-traceparent). ### `traceIgnoreStatusCodes` @@ -308,45 +249,7 @@ Depending on the platform, other default data may be included. (For example, for ### Propagation -A transaction's sampling decision should be passed to all of its children, including across service boundaries. This can be accomplished in the `startChild` method for same-service children and using the `sentry-trace` header for children in a different service. - -### Propagated Random Value - -To improve the likelihood of capturing complete traces when backend services use a custom sample rate via `tracesSampler`, the SDK propagates the same random value used for sampling decisions across all services in a trace. This ensures consistent sampling decisions across a trace instead of generating a new random value for each service. - -The random value (`sample_rand`) is set according to the following rules: - -1. A `sample_rand` is a float (`0.123456` notation) in the range of `[0, 1)` (including 0.0, excluding 1.0), with six digits after the decimal point. -1. When tracing is enabled and a new trace is started, the SDK generates a `sample_rand` value for the current execution context. - 1. This also applies to Tracing without Performance where we simply want to generate `sample_rand` every time a new trace is started. This `sample_rand` value can then be stored on `PropagationContext`. -1. It is _recommended_ to generate the random number deterministically using the trace ID as seed or source of randomness (make sure to do this atomically so multiple threads accessing the same random instance don't mix their seeds). The exact method by which the random number is created is implementation-defined and may vary between SDK implementations. -1. The `sample_rand` is part of the DSC (Dynamic Sampling Context) and as with other values on the `baggage` header, the `sample_rand` value from the current execution context should be propagated to downstream SDKs. It should also be sent to other system as part of the `baggage` header if Performance is disabled and sampling decision is deferred. -1. On incoming traces, an SDK takes the incoming `sentry-sample_rand` value in the `baggage` header and uses it for the rest of the current execution context (for example, request) by storing it in the `PropagationContext`. -1. If `sample_rand` is missing on an incoming trace, the SDK creates a new one applying **special rules** and uses it for the current execution context: - 1. If `sample_rate` (inside `baggage`) and the sampling decision (trailing `-1` or `-0` from the `sentry-trace` header) are present in the incoming trace, create `sample_rand` so that when compared to the incoming `sample_rate` it would lead to the same sampling decision that is in the `sentry-trace` header. This means, for a decision of `True` generate a random number in half-open range `[0, rate)` and for a decision of `False` generate a random number in range `[rate, 1)`. - 1. If the sampling decision is missing on the incoming trace, generate a random number in range of `[0, 1)` (including 0.0, excluding 1.0), like for a new trace. - -The SDK should always use the stored random number (`sentry-sample_rand`) for sampling decisions and should not directly rely on `math.random()` when deciding to sample or not: - -1. When the `tracesSampler` is invoked, the return value should be compared with `sample_rand`: `trace["sentry-sample_rand"] < tracesSampler(context)` -1. When there is an incoming trace, the SDK fully inherits incoming sampling decisions from the `sentry-trace` header. -1. Otherwise, when the SDK is the head of a trace (and `tracesSampleRate` is defined), the sampling is done comparing the `tracesSampleRate` with the `sample_rand`: `trace["sentry-sample_rand"] < config.tracesSampleRate` - -Something that should be documented for every SDK is the recommended way to use a `tracesSampler` to inherit the parent's sampling decision using the `parentSampleRate`. This way, Sentry can still extrapolate counts correctly: - -```js -tracesSampler: ({ name, parentSampleRate }) => { - // Inherit the trace parent's sample rate if there is one. Sampling is deterministic - // for one trace, i.e. if the parent was sampled, we will be sampled too at the same - // rate. - if (typeof parentSampleRate === "number") { - return parentSampleRate; - } - - // Else, use default sample rate (replacing tracesSampleRate). - return 0.5; -}, -``` +See [Trace Propagation: Sampling Decision Propagation](/sdk/foundations/trace-propagation/#sampling-decision-propagation) and [Propagated Random Value](/sdk/foundations/trace-propagation/#propagated-random-value). ### Backpressure @@ -354,39 +257,7 @@ If the SDK supports backpressure handling, the overall sampling rate needs to be ## Header `sentry-trace` -The header is used for trace propagation. SDKs use the header to continue traces from upstream services (incoming HTTP requests), and to propagate tracing information to downstream services (outgoing HTTP requests). - -`sentry-trace = traceid-spanid-sampled` - -`sampled` is optional. So at a minimum, it's expected: - -`sentry-trace = traceid-spanid` - -To offer a minimal compatibility with the [W3C `traceparent` header](https://www.w3.org/TR/trace-context/#traceparent-header) (without the version prefix) and [Zipkin's `b3` headers](https://zipkin.io/pages/instrumenting#communicating-trace-information) (which consider both 64 and 128 bits for `traceId` valid), the `sentry-trace` header should have a `traceId` of 128 bits encoded in 32 hex chars and a `spanId` of 64 bits encoded in 16 hex chars. -To avoid confusion with the W3C `traceparent` header (to which our header is similar but not identical), we call it simply `sentry-trace`. -No version is being defined in the header. - -The `sentry-trace` header should only be attached to an outgoing request if the request's URL matches at least one entry of the [`tracePropagationTargets`](#tracepropagationtargets) SDK option or this options is set to `null`. - -### The `sampled` Value - -To simplify processing, the value consists of a single (optional) character. The possible values are: - -``` - - No value means defer - -0 - Don't sample - -1 - Sampled -``` - -Unlike with `b3` headers, a `sentry-trace` header should never consist solely of a sampling decision, with no `traceid` or `spanid` values. There are [good reasons](https://github.com/apache/incubator-zipkin-b3-propagation/blob/bc937b6854ea30e46b3e85fbf147d8f4de685dd5/README.md#why-send-trace-ids-with-a-reject-sampling-decision) to always include the `traceid` and `spanid` regardless of the sampling decision, and doing so also simplifies implementation. - -Besides the [usual reasons to use \*defer](https://github.com/apache/incubator-zipkin-b3-propagation/blob/bc937b6854ea30e46b3e85fbf147d8f4de685dd5/README.md#why-defer-a-sampling-decision),\* in the case of Sentry, a reason would be if a downstream system captures an error event with Sentry. The decision could be done at that point to sample that trace in order to have tracing data available for the reported crash. - -`sentry-trace = sampled` - -Which in reality is useful for proxies to set it to `0` and opt out of tracing. +See [Trace Propagation: sentry-trace Header](/sdk/foundations/trace-propagation/#sentry-trace-header) for the full header format and sampling value specification. ## Static API Changes diff --git a/develop-docs/sdk/telemetry/traces/trace-propagation-cheat-sheet.mdx b/develop-docs/sdk/telemetry/traces/trace-propagation-cheat-sheet.mdx deleted file mode 100644 index f5a1a7756493b..0000000000000 --- a/develop-docs/sdk/telemetry/traces/trace-propagation-cheat-sheet.mdx +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Trace Propagation Cheat Sheet ---- - -This is a cheat sheet where you can see how the trace propagation work in SDKs in different scenarios. - -| SCENARIO:
Incoming trace in `sentry-trace/baggage` headers | SCENARIO:
Incoming sampled flag in `sentry-trace/baggage` header | SCENARIO:
`traces_propagation_targets` are matching? | SCENARIO:
`traces_sample_rate` setting | OUTCOME:
Send Spans to Sentry? | OUTCOME:
Outgoing Requests Have Trace? (`sentry-trace/baggage` are present) | OUTCOME:
Continue Incoming Trace? (outgoing `trace_id` is the incoming `trace_id`) | -| -------------------------------------------------------------- | :------------------------------------------------------------------: | :------------------------------------------------------: | :----------------------------------------: | :--------------------------------: | :-----------------------------------------------------------------------------: | :------------------------------------------------------------------------------------: | -| not present | - | yes | null | no | yes | - | -| not present | - | yes | 0 | no | yes | - | -| not present | - | yes | 1 | yes | yes | - | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| not present | - | no | null | no | no | - | -| not present | - | no | 0 | no | no | - | -| not present | - | no | 1 | yes | no | - | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | empty (deferred) | yes | null | no | yes | yes | -| present | empty (deferred) | yes | 0 | no | yes | yes | -| present | empty (deferred) | yes | 1 | yes | yes | yes | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | 1 | yes | null | no | yes | yes | -| present | 1 | yes | 0 | yes | yes | yes | -| present | 1 | yes | 1 | yes | yes | yes | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | 0 | yes | null | no | yes | yes | -| present | 0 | yes | 0 | no | yes | yes | -| present | 0 | yes | 1 | no | yes | yes | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | empty (deferred) | no | null | no | no | - | -| present | empty (deferred) | no | 0 | no | no | - | -| present | empty (deferred) | no | 1 | yes | no | - | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | 1 | no | null | no | no | - | -| present | 1 | no | 0 | yes | no | - | -| present | 1 | no | 1 | yes | no | - | -| -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -------------------- | -| present | 0 | no | null | no | no | - | -| present | 0 | no | 0 | no | no | - | -| present | 0 | no | 1 | no | no | - | - -## FAQ - -**Why are we sometimes sampling even if `traces_sample_rate` is 0? Why are we sometimes unsampling if `traces_sample_rate` is 1?** - -A `traces_sample_rate` between 0 and 1 is only taken into account if there is no incoming trace and the SDK has to make its own sampling decision. If there is an incoming trace, the parent sampling decision always takes precedence over `traces_sample_rate`. diff --git a/develop-docs/sdk/telemetry/traces/tracing-without-performance.mdx b/develop-docs/sdk/telemetry/traces/tracing-without-performance.mdx deleted file mode 100644 index b46d6328816bc..0000000000000 --- a/develop-docs/sdk/telemetry/traces/tracing-without-performance.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Tracing Without Performance ---- - -If Sentry SDKs are not configured for sending spans (or transactions), they should fall back to a mode where they still handle continuing and propagating traces. -Internally, we call this mode "Tracing without Performance", or "TwP" in short ([learn more why](#historical-context)). -TwP mode ensures that error events and other signals are still connected via a trace, even if users choose not to send spans or performance data. - -## Behavior - -Tracing without Performance is the default fallback behavior of SDKs, when users [don't specify any tracing options](#configuration). - -This means that SDKs by default always: - -- continue incoming traces -- attach `event.contexts.trace` context on events (e.g. errors, check-ins, replays) -- attach the `trace` envelope header to Sentry envelopes, populated from the dynamic sampling context -- propagate trace data (`sentry-trace`, `baggage`) via the usual channels (e.g. HTTP headers, `` HTML elements, etc), with the correct [sampling decision](#sampling-decision) - -## Configuration - -TwP is active by default if users don't specify sampling options that enable span collection and sending (i.e. [regular tracing](#enable-regular-tracing)). -For example, the following trivial SDK setup (note the absence of sampling options) enables TwP: - -```javascript -Sentry.init({ - dsn: "___PUBLIC_DSN___", -}); -``` - -TwP mode is exited by configuring the SDK for [regular tracing](#enable-regular-tracing) or partially disabled by [opting out of trace propagation](#disable-trace-propagation). - - - -Note that some SDKs like the JavaScript Browser SDK require additional integrations to enable tracing all together. -This is fine as long as there's a good reason why additional configuration is required (like keeping bundle size in check in JS). - - - -### Enable Regular Tracing - -As soon as users specify a tracing option in the SDK configuration, SDKs will use the normal tracing mode, which means collecting and sending spans (or transactions) in addition to continuing and propagating traces. - -This can be achieved by specifying `tracesSampleRate` or `tracesSampler`, or any other equivalent option in the SDK configuration: - -```js -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 0.1, - // or - tracesSampler: () => { - /*...*/ - }, -}); -``` - -It's important to note that setting `tracesSampleRate: 0` does not mean that we fall back to TwP mode but that sampling decisions are always negative and we propagate the trace with a negative sampling decision. - -### Disable Trace Propagation - -To opt out of further propagating a trace, users can pass an empty array (or language-equivalent parameter) to the [`tracePropagationTargets` option](/sdk/telemetry/traces/#tracepropagationtargets). This will prevent the SDK from propagating trace information any further. - -```js -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracePropagationTargets: [], -}); -``` - -Note, that for incoming requests with trace headers, SDKs should still continue this trace, but not propagate it further downstream. - -## Implementation - -SDKs implementing TwP mode must adhere to the behavior described in this section. -Everything else (e.g. how to store the trace data and specific tracing options) is considered an implementation detail and can be implemented as needed. - -### Continuing Incoming Traces - -SDKs in TwP mode must continue incoming traces (e.g. from incoming HTTP requests) if available and attach the trace data of the continued trace to any events that are created during the lifetime of this trace. -Furthermore, they must propagate the continued trace as usual on all outgoing requests. -This means that continuing traces should work just like in the regular tracing mode (with spans). - -At the time of writing this document, there is no way to opt out of continuing incoming traces in TwP mode, unless users manually start a new trace. - -### Starting a New Trace - -If an SDK in TwP mode doesn't receive an incoming trace, it should start a new trace. -In this case, the new trace is not sampled (as in, there is no sampling decision, neither positive nor negative). -Instead, the sampling decision is _deferred_ to the next downstream SDK. - -This means that: - -- the SDK must not include a sampled flag in the [`sentry-trace` header](../#header-sentry-trace), meaning the header has the format `-`. - More details on the [sampled flag](../#the-sampled-value). -- the [dynamic sampling context](https://develop.sentry.dev/sdk/telemetry/traces/dynamic-sampling-context/), propagated via `baggage` must not contain the `sentry-sampled` key. - -### Attaching Trace Data to Events and Envelopes - -Any event created by an SDK in TwP mode must include the [`trace` context](/sdk/foundations/transport/event-payloads/contexts/#trace-context). -This context should contain the trace data of the current trace, if available, just like in regular tracing mode. - -Furthermore, the [`trace` envelope header](/sdk/telemetry/traces/dynamic-sampling-context/#envelope-header) (populated from the dynamic sampling context) must be attached to any outgoing event envelope. - -### Trace Duration and Storage - -Traces in TwP mode should have the same duration as regular traces. -For example, a TwP trace for a backend server should generally last for the duration of one individual request. -This usually corresponds with the lifetime of an [isolation scope](/sdk/foundations/state-management/scopes/#isolation-scope) (or current scope created within the isolation scope). - -SDKs in TwP mode must store trace data in a way that makes it possible for them to be attached to events and propagated to outgoing requests. -The exact storage mechanism is up to the SDK implementation, but we recommended using the same mechanism as for regular traces. -Usually this means storing the data on the scope in a field called `propagationContext` as [recommended here](/sdk/telemetry/traces/distributed-tracing/). - -On a related note, the `propagationContext` should be populated with a random `traceId` and `spanId` if no incoming trace is present. -This—in combination with the [`sentry-trace` header specification](/sdk/telemetry/traces/#header-sentry-trace) requiring a `spanId`—has an important implication on the Sentry product: -A non-existing `spanId` will be propagated along with the trace and attached to events. -While not ideal, we accept this limitation as the Sentry product can and should handle non-existing (parent) spans anyway. - -As in regular tracing mode, for SDKs starting a new trace, the [Dynamic Sampling Context](/sdk/telemetry/traces/dynamic-sampling-context/) should be lazily populated and frozen for the duration of the trace. -Given that no span is actually available in TwP mode, the DSC will not contain any keys related to spans (`transaction`, `sample_rate` or `sampled`). - -In SDKs adapting OpenTelemetry's tracing capabilities ([POTel](/sdk/foundations/state-management/scopes/#otel-context-alignment)), the TwP trace data could also be stored in a non-recording span. -For Example, the Node SDK also starts non-recording Otel spans in TwP mode and takes the trace data from them. In case no span is started (e.g. a node script without request handling), it falls back to the propagation context on the scope. -Note that in the case of using the non-recording span, the span is also not sampled, meaning the sampling decision must still be deferred [when starting a new Trace](#starting-a-new-trace). - -## Historical Context - -TwP mode was introduced after SDKs were already capable of sending spans and transactions. Before TwP, SDKs would only handle traces if span-sending was enabled. Otherwise, neither trace data would be attached to any events nor were traces propagated further downstream. - -The primary motivation for TwP was to ensure that errors across application or service boundaries were still connected if they occurred in the same trace. - -The name "Tracing without Performance" was chosen because at the time of introduction, we associated spans purely with performance monitoring. -Today, we associate spans with "Tracing" in general, and only (some of) the data from spans with Performance Monitoring. -This is why the name from today's perspective is a bit misleading. -As a mental model, think of TwP as "Trace propagation and continuation without Spans". diff --git a/develop-docs/sdk/telemetry/user-reports.mdx b/develop-docs/sdk/telemetry/user-reports.mdx index 8bb39767b6540..e73c200c1dbb0 100644 --- a/develop-docs/sdk/telemetry/user-reports.mdx +++ b/develop-docs/sdk/telemetry/user-reports.mdx @@ -37,10 +37,10 @@ User reports continue to work so older SDKs won't break. If both the item and it ## Wire Format -### Envelope Item - +### Envelope Item + Item type `"user_report"`. The item contains a JSON payload: ```json @@ -80,10 +80,10 @@ _None_ ## Public API -### Capture User Feedback (Deprecated) - +### Capture User Feedback (Deprecated) + ``` captureUserFeedback(userFeedback) -> void ``` diff --git a/redirects.js b/redirects.js index 9b57ef9196c6d..b6ec385fc71a3 100644 --- a/redirects.js +++ b/redirects.js @@ -13,7 +13,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/getting-started/playbooks/handling-external-contributor-pr/', - destination: '/sdk/getting-started/playbooks/development/handling-external-contributor-pr/', + destination: + '/sdk/getting-started/playbooks/development/handling-external-contributor-pr/', }, { source: '/sdk/getting-started/playbooks/opening-a-pr/', @@ -25,7 +26,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/getting-started/playbooks/reviewing-ai-generated-code/', - destination: '/sdk/getting-started/playbooks/development/reviewing-ai-generated-code/', + destination: + '/sdk/getting-started/playbooks/development/reviewing-ai-generated-code/', }, { source: '/sdk/getting-started/playbooks/syncing-feature-branches/', @@ -33,7 +35,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/getting-started/playbooks/aligning-cross-sdk-changes/', - destination: '/sdk/getting-started/playbooks/coordination/aligning-cross-sdk-changes/', + destination: + '/sdk/getting-started/playbooks/coordination/aligning-cross-sdk-changes/', }, { source: '/sdk/getting-started/playbooks/quarterly-cross-sdk-retro/', @@ -53,7 +56,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/getting-started/playbooks/dropping-platform-support/', - destination: '/sdk/getting-started/playbooks/sdk-lifecycle/dropping-platform-support/', + destination: + '/sdk/getting-started/playbooks/sdk-lifecycle/dropping-platform-support/', }, { source: '/sdk/getting-started/playbooks/setting-up-new-sdk-repo/', @@ -61,7 +65,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/getting-started/playbooks/setting-up-release-infrastructure/', - destination: '/sdk/getting-started/playbooks/setup/setting-up-release-infrastructure/', + destination: + '/sdk/getting-started/playbooks/setup/setting-up-release-infrastructure/', }, { source: '/sdk/miscellaneous/unified-api/tracing/:path*', @@ -83,6 +88,23 @@ const developerDocsRedirects = [ source: '/api/:path*', destination: '/application/api/:path*', }, + // Context propagation consolidation (must be before the /sdk/performance/ wildcard) + { + source: '/sdk/performance/dynamic-sampling-context/', + destination: '/sdk/foundations/trace-propagation/dynamic-sampling-context/', + }, + { + source: '/sdk/performance/dynamic-sampling-context/:path*', + destination: '/sdk/foundations/trace-propagation/dynamic-sampling-context/:path*', + }, + { + source: '/sdk/performance/distributed-tracing/', + destination: '/sdk/foundations/trace-propagation/', + }, + { + source: '/sdk/performance/distributed-tracing/:path*', + destination: '/sdk/foundations/trace-propagation/:path*', + }, { source: '/sdk/performance/:path*', destination: '/sdk/telemetry/traces/:path*', @@ -300,7 +322,8 @@ const developerDocsRedirects = [ }, { source: '/sdk/processes/releases/', - destination: '/sdk/getting-started/playbooks/setup/setting-up-release-infrastructure/', + destination: + '/sdk/getting-started/playbooks/setup/setting-up-release-infrastructure/', }, { source: '/sdk/processes/triaging/', @@ -450,6 +473,35 @@ const developerDocsRedirects = [ source: '/sdk/expected-features/environment-variables/', destination: '/sdk/foundations/client/configuration/', }, + // Context propagation consolidation + { + source: '/sdk/telemetry/traces/distributed-tracing/', + destination: '/sdk/foundations/trace-propagation/', + }, + { + source: '/sdk/telemetry/traces/distributed-tracing/:path*', + destination: '/sdk/foundations/trace-propagation/:path*', + }, + { + source: '/sdk/telemetry/traces/dynamic-sampling-context/', + destination: '/sdk/foundations/trace-propagation/dynamic-sampling-context/', + }, + { + source: '/sdk/telemetry/traces/dynamic-sampling-context/:path*', + destination: '/sdk/foundations/trace-propagation/dynamic-sampling-context/:path*', + }, + { + source: '/sdk/telemetry/traces/tracing-without-performance/', + destination: '/sdk/foundations/trace-propagation/#default-propagation', + }, + { + source: '/sdk/telemetry/traces/trace-propagation-cheat-sheet/', + destination: '/sdk/foundations/trace-propagation/#propagation-decision-matrix', + }, + { + source: '/sdk/telemetry/spans/span-trace-propagation/', + destination: '/sdk/foundations/trace-propagation/#continue-trace', + }, ]; /** @type {import('next/dist/lib/load-custom-routes').Redirect[]} */ diff --git a/src/components/specSection.tsx b/src/components/specSection.tsx index 816198e0c21c8..f8b80e7d150fc 100644 --- a/src/components/specSection.tsx +++ b/src/components/specSection.tsx @@ -34,20 +34,29 @@ export function SpecSection({ const {label, borderColor} = STATUS_CONFIG[status]; const badgeClass = SPEC_STATUS_BADGE[status]; + // Split children: first element is the heading (rendered outside the border), + // the rest is body content (rendered inside the colored border strip). + const childArray = Array.isArray(children) ? children : [children]; + const heading = childArray[0]; + const body = childArray.slice(1); + return ( -
-
- - {label} - - since {since} - {superseded_by && ( - - Superseded by {superseded_by} +
+
{heading}
+
+
+ + {label} - )} + specified since {since} + {superseded_by && ( + + Superseded by {superseded_by} + + )} +
+
{body}
-
{children}
); }