You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document uses standard interval notation, where `[` and `]` denote closed intervals which include the endpoints of the interval, while `(` and `)` denote open intervals which exclude the endpoints of the interval. An interval `[x, y)` covers all values starting from `x` up to but excluding `y`.
20
+
21
+
</Note>
22
+
16
23
## SDK Configuration
17
24
18
25
This section describes the options SDKs should expose to configure tracing and performance monitoring.
@@ -25,13 +32,13 @@ This option is **deprecated** and should be removed from all SDKs.
25
32
26
33
### `tracesSampleRate`
27
34
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`.
35
+
This should be a float point number in the range `[0, 1]`and represents the percentage chance that any given transaction will be sent to Sentry. So, barring [outside influence](#sampling), `0.0` is a guaranteed 0% chance (none will be sent) and `1.0` is a guaranteed 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`.
29
36
30
37
See more about how sampling should be performed [below](#sampling).
31
38
32
39
### `tracesSampler`
33
40
34
-
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`).
41
+
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 in range `[0, 1]`_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`).
35
42
36
43
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.
37
44
@@ -161,7 +168,7 @@ tree as well as the unit of reporting to Sentry.
161
168
162
169
## Sampling
163
170
164
-
Each transaction has a "sampling decision," that is, a boolean which dictates whether or not it should be sent to Sentry. This should be set exactly once during a transaction's lifetime, and should be stored in an internal `sampled` boolean.
171
+
Each transaction has a _sampling decision_, that is, a boolean which declares whether or not it should be sent to Sentry. This should be set exactly once during a transaction's lifetime, and should be stored in an internal `sampled` boolean.
165
172
166
173
There are multiple ways a transaction can end up with a sampling decision:
167
174
@@ -171,7 +178,7 @@ There are multiple ways a transaction can end up with a sampling decision:
171
178
- If the transaction has a parent, inheriting its parent's sampling decision
172
179
- Absolute decision passed to `startTransaction`
173
180
174
-
When there's the potential for more than one of these to come into play, the following precedence rules should apply:
181
+
When there's the potential for more than one of these to apply, the following precedence rules should apply:
175
182
176
183
1. If a sampling decision is passed to `startTransaction` (`startTransaction({name: "my transaction", sampled: true})`), that decision will be used, regardlesss of anything else
177
184
2. If `tracesSampler` is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, or use the sampling context data to make its own decision or choose a sample rate for the transaction.
@@ -201,25 +208,34 @@ Depending on the platform, other default data may be included. (For example, for
201
208
202
209
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.
203
210
204
-
### Propagated Sampling Rates
211
+
### Propagated Random Value
212
+
213
+
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 sampling with a different random value in every service. Therefore, across a trace every SDK uses the same random value.
205
214
206
-
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.
215
+
Without a `tracesSampler` callback, an SDK fully inherits sampling decisions for propagated traces. In this case, the presence of `sample_rand` in the DSC has no effect on the sampling decision. However, this behavior is subject to change in the future.
207
216
208
-
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.
217
+
The random value is set according to the following rules:
209
218
210
-
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.
219
+
1. When an SDK starts a new trace, `sample_rand` is always set to a truly random number in range `[0, 1]`. This explicitly includes traces that are not sampled, as well as when the `tracesSampleRate` is set to `0.0` or `1.0`.
220
+
2. It is _recommended_ to generate the random number deterministically using the trace ID as seed or source of randomness. The exact method by which the random number is created is implementation defined and may vary between SDK implementations.
221
+
3. On incoming traces, an SDK assumes the `sample_rand` value along with the rest of the DSC, overriding an existing value if needed.
222
+
4. If `sample_rand` is missing on an incoming trace, the SDK creates and from now on propagates a new random number on-the-fly, based on the following rules:
223
+
1. If `sample_rate` and `sampled` are propgated, create `sample_rand` so that it adheres to the invariant. 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]`.
224
+
2. If only `sampled` is propagated, apply the same strategy above using the output of the `tracesSampler` + `tracesSampleRate` cascade as cutoff point for the intervals.
225
+
3. If the `sampled` is missing `sample_rate`, generate a random number in the range `[0, 1]` like for a new trace.
211
226
212
-
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.
227
+
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:
213
228
214
-
- When the `tracesSampler` is invoked, this also applies to the return value of traces sampler. i.e. `trace["sentry-sample_rand"] < tracesSampler(context)`
215
-
- 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`
229
+
1. When the `tracesSampler` is invoked, this also applies to the return value of traces sampler. That is, `trace["sentry-sample_rand"] < tracesSampler(context)`
230
+
2. Otherwise, when the SDK is the head of a trace, this also applies to sample decisions based on `tracesSampleRate`. That is, `trace["sentry-sample_rand"] < config.tracesSampleRate`
231
+
3. There is no more direct comparison with `math.random()` during the sampling process.
216
232
217
-
When using a `tracesSampler`, the 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.
233
+
When using a `tracesSampler`, the 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, Sentry can still extrapolate counts correctly.
218
234
219
235
```js
220
236
tracesSampler: ({ name, parentSampleRate }) => {
221
-
// Inherit the trace parent's sample rate if there is one. Sampling is deterministic
222
-
// for one trace, i.e. if the parent was sampled, we will be sampled too at the same
237
+
// Inherit the trace parent's sample rate if there is one. Sampling is deterministic
238
+
// for one trace, i.e. if the parent was sampled, we will be sampled too at the same
0 commit comments