Skip to content

Commit e79e54a

Browse files
committed
Propagated Sampling Rates
1 parent 406b7a6 commit e79e54a

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

develop-docs/sdk/telemetry/traces/dynamic-sampling-context.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ To align DSC propagation over all our SDKs, we defined a [unified propagation me
4949
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.
5050

5151
At the moment, only `release`, `environment` and `transaction` are used by the product for dynamic sampling functionality.
52-
The rest of the context attributes, `trace_id`, `public_key`, and `sample_rate`, are used by Relay for internal decisions (like transaction sample rate smoothing).
52+
The rest of the context attributes, `trace_id`, `public_key`, `sampled` and `sample_rate`, are used by Relay for internal decisions (like transaction sample rate smoothing).
53+
Additional entries such as `replay_id`, `org` and `sample_rand` are only using the DSC as a mean of transport.
5354

5455
| Attribute | Type | Description | Example | Required Level |
5556
| --------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | ------------------------------------ |
@@ -60,6 +61,8 @@ The rest of the context attributes, `trace_id`, `public_key`, and `sample_rate`,
6061
| `release` | string | The release name as specified in client options. | `[email protected]`, `1.2.3`, `2025.4.107` | required |
6162
| `environment` | string | The environment name as specified in client options. | `production`, `staging` | required |
6263
| `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) |
64+
| `org` | string | The org ID parsed from the DSN or received by a downstream SDK. | `1` | required |
65+
| `sample_rand` | string | A trully random number originating from the head of trace SDK. | `0.5` | required |
6366
| `user_segment` [DEPRECATED] | string | User segment as set by the user with `scope.set_user()`. | | deprecated |
6467

6568
0: In any case, `trace_id`, `public_key`, and `sample_rate` should always be known to an SDK, so these values are strictly required.

develop-docs/sdk/telemetry/traces/index.mdx

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@ Reference implementations:
1717

1818
This section describes the options SDKs should expose to configure tracing and performance monitoring.
1919

20-
Tracing is enabled by setting any of three SDK config options, `enableTracing`, `tracesSampleRate` and `tracesSampler`. If not set, these options default to `undefined`, making tracing opt-in.
20+
Tracing is enabled by setting either a `tracesSampleRate` or `tracesSampler`. If not set, these options default to `undefined` or `null`, making tracing opt-in.
2121

2222
### `enableTracing`
2323

24-
This option shall enable the generation of transactions and propagation of trace data. Sample rates shall be set at a default which is practical to the specific platform. Users may use the other options, listed below, should their use case require it. The standard should be to set the default sample rate at 100%, and only working back if there are inherent concerns for that platform. Users should be able to send most if not all of their data and rely on Sentry server side processing of their data.
24+
This option is **deprecated** and should be removed from all SDKs.
2525

2626
### `tracesSampleRate`
2727

28-
This should be a float/double between `0.0` and `1.0` (inclusive) and represents the percentage chance that any given transaction will be sent to Sentry. So, barring [outside influence](https://develop.sentry.dev/sdk/performance/#sampling), `0.0` is a 0% chance (none will be sent) and `1.0` is a 100% chance (all will be sent). This rate applies equally to all transactions; in other words, each transaction should have the same random chance of ending up with `sampled = true`, equal to the `tracesSampleRate`.
28+
This should be a float/double between `0.0` and `1.0` (inclusive) and represents the percentage chance that any given transaction will be sent to Sentry. So, barring [outside influence](#sampling), `0.0` is a 0% chance (none will be sent) and `1.0` is a 100% chance (all will be sent). This rate applies equally to all transactions; in other words, each transaction should have the same random chance of ending up with `sampled = true`, equal to the `tracesSampleRate`.
2929

30-
See more about how sampling should be performed below.
30+
See more about how sampling should be performed [below](#sampling).
3131

3232
### `tracesSampler`
3333

3434
This should be a callback, called when a transaction is started, which will be given a `samplingContext` object and which should return a sample rate between `0.0` and `1.0` _for the transaction in question_. This sample rate should behave the same way as the `tracesSampleRate` above, with the difference that it only applies to the newly-created transaction, such that different transactions can be sampled at different rates. Returning `0.0` should force the transaction to be dropped (set to `sampled = false`) and returning `1.0` should force the transaction to be sent (set `sampled = true`).
3535

36-
Optionally, the `tracesSampler` callback can also return a boolean to force a sampling decision (with `false` equivalent to `0.0` and `true` equivalent to `1.0`). If returning two different datatypes isn't an option in the implementing language, this possibility can safely be omitted.
36+
Historically, the `tracesSampler` callback could have also returned a boolean to force a sampling decision (with `false` equivalent to `0.0` and `true` equivalent to `1.0`). This behavior is now **deprecated** and should be removed from all SDKs.
3737

38-
See more about how sampling should be performed below.
38+
See more about how sampling should be performed [below](#sampling).
3939

4040
### `tracePropagationTargets`
4141

@@ -65,6 +65,20 @@ This Option replaces the non-standardized `tracingOrigins` option which was prev
6565

6666
</Alert>
6767

68+
### `strictTracePropagation`
69+
70+
This option disables trace continuation from unknown 3rd party services that happen to be instrumented by a Sentry SDK.
71+
72+
If the SDK can parse an org ID from the configured DSN, this value must be propagated as a baggage entry with the key `sentry-org`. Given a DSN of `https://[email protected]/1`, the org ID is `1`, based on `o1`.
73+
74+
On incoming traces, the SDK must compare the `sentry-org` baggage value against its own parsed value from the DSN. Only if both match, the parent sampling decisions applies.
75+
76+
This behavior can be disabled by setting `strictTracePropagation: false` in the SDK init call.
77+
Initially, SDKs should introduce the this option with a default values of `false`.
78+
Once the majority of SDKs introduced this option, we will make it opt-out in a major version.
79+
80+
The SDK must be configurable with an optional `org: <org-id>` 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 none standard Sentry DSN is used, such as when using a local Relay.
81+
6882
### `traceOptionsRequests`
6983

7084
This should be a boolean value. Default is `false`. When set to `true` transactions should be created for HTTP `OPTIONS` requests. When set to `false` NO transactions should be created for HTTP `OPTIONS` requests. This configuration is most valuable on backend server SDKs. If this configuration does not make sense for an SDK it can be omitted.
@@ -176,6 +190,7 @@ Transactions should be sampled only by `tracesSampleRate` or `tracesSampler`. Th
176190
If defined, the `tracesSampler` callback should be passed a `samplingContext` object, which should include, at minimum:
177191

178192
- The `transactionContext` with which the transaction was created
193+
- A float/double `parentSampleRate` which contains the sampling rate passed down from the parent
179194
- A boolean `parentSampled` which contains the sampling decision passed down from the parent, if any
180195
- Data from an optional `customSamplingContext` object passed to `startTransaction` when it is called manually
181196

@@ -185,6 +200,35 @@ Depending on the platform, other default data may be included. (For example, for
185200

186201
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 `senry-trace` header for children in a different service.
187202

203+
### Propagated Sampling Rates
204+
205+
To increase the chance of capturing complete traces when users return a new sample rate from the `tracesSampler` in backend services, we propagate the generated random value used by the SDK for computing the sampling decision instead of creating a new random value in every service. Therefore, across a trace every SDK uses the same random value.
206+
207+
The behavior of the static `tracesSampleRate` without the use of `tracesSampler` does not change. We continue to fully inherit sampling decisions for propagated traces and create a new one for started traces. In the future, we might change the default behavior of `tracesSampleRate`, too.
208+
209+
Once the SDK starts a new trace, `sentry-sample_rand` is filled with a truly random number. This also applies when the `tracesSampleRate` is set to `1.0`. If the SDK receives an incoming trace, containing a `sentry-sample_rand` entry in the baggage, this value should overwrite the currently stored number. For incoming traces without a `sentry-sample_rand` baggage entry (from old SDKs), the SDK inserts a new truly random number on-the-fly.
210+
211+
The SDK should exclusively use the stored random number and no longer use `math.random()` or similar anywhere else in the tracing related code base.
212+
213+
- When the `tracesSampler` is invoked, this also applies to the return value of traces sampler. i.e. `trace["sentry-sample_rand"] < tracesSampler(context)`
214+
- Otherwise, when the SDK is the head of a trace, this applies to sample decisions based on `tracesSampleRate` , i.e. `trace["sentry-sample_rand"] < config.tracesSampleRate`
215+
216+
When using a `tracesSampler`, the most correct way to inherit parent sampling decisions is now to return the parent's sample rate instead of the decision as float (1.0). This way, we can still extrapolate counts correctly.
217+
218+
```js
219+
tracesSampler: ({ name, parentSampleRate }) => {
220+
// Inherit the trace parent's sample rate if there is one. Sampling is deterministic
221+
// for one trace, i.e. if the parent was sampled, we will be sampled too at the same
222+
// rate.
223+
if (typeof parentSampleRate === "number") {
224+
return parentSampleRate;
225+
}
226+
227+
// Else, use default sample rate (replacing tracesSampleRate).
228+
return 0.5;
229+
},
230+
```
231+
188232
### Backpressure
189233

190234
If the SDK supports backpressure handling, the overall sampling rate needs to be divided by the `downsamplingFactor` from the backpressure monitor. See [the backpressure spec](/sdk/performance/backpressure/#downsampling) for more details.

0 commit comments

Comments
 (0)