diff --git a/CHANGELOG.md b/CHANGELOG.md index 9041036f9c5..531c939449e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ release. ### Traces +- Define sampling threshold field in OpenTelemetry TraceState; define the behavior + of TraceIdRatioBased sampler in terms of W3C Trace Context Level 2 randomness. + ([#4166](https://github.com/open-telemetry/opentelemetry-specification/pull/4166)) + ### Metrics ### Logs diff --git a/spec-compliance-matrix.md b/spec-compliance-matrix.md index d2c47e48ea5..bcfb269ff18 100644 --- a/spec-compliance-matrix.md +++ b/spec-compliance-matrix.md @@ -87,6 +87,7 @@ formats is required. Implementing more than one format is optional. | [Built-in `SpanProcessor`s implement `ForceFlush` spec](specification/trace/sdk.md#forceflush-1) | | | + | | + | + | + | + | + | + | + | | | [Attribute Limits](specification/common/README.md#attribute-limits) | X | | + | | + | + | + | + | | | | | | Fetch InstrumentationScope from ReadableSpan | | | + | | + | | | + | | | | | +| TraceIdRatioBased sampler implements OpenTelemetry tracestate `th` field | | | | | | | | | | | | | ## Baggage diff --git a/specification/trace/sdk.md b/specification/trace/sdk.md index 765edc4b296..28bf2a14ded 100644 --- a/specification/trace/sdk.md +++ b/specification/trace/sdk.md @@ -30,7 +30,10 @@ linkTitle: SDK + [AlwaysOn](#alwayson) + [AlwaysOff](#alwaysoff) + [TraceIdRatioBased](#traceidratiobased) - - [Requirements for `TraceIdRatioBased` sampler algorithm](#requirements-for-traceidratiobased-sampler-algorithm) + - [`TraceIdRatioBased` sampler configuration](#traceidratiobased-sampler-configuration) + - [`TraceIdRatioBased` sampler algorithm](#traceidratiobased-sampler-algorithm) + - [`TraceIdRatioBased` sampler description](#traceidratiobased-sampler-description) + - [`TraceIdRatioBased` sampler compatibility warning](#traceidratiobased-sampler-compatibility-warning) + [ParentBased](#parentbased) + [JaegerRemoteSampler](#jaegerremotesampler) - [Span Limits](#span-limits) @@ -386,40 +389,78 @@ The default sampler is `ParentBased(root=AlwaysOn)`. #### TraceIdRatioBased -* The `TraceIdRatioBased` MUST ignore the parent `SampledFlag`. To respect the -parent `SampledFlag`, the `TraceIdRatioBased` should be used as a delegate of -the `ParentBased` sampler specified below. -* Description MUST return a string of the form `"TraceIdRatioBased{RATIO}"` - with `RATIO` replaced with the Sampler instance's trace sampling ratio - represented as a decimal number. The precision of the number SHOULD follow - implementation language standards and SHOULD be high enough to identify when - Samplers have different ratios. For example, if a TraceIdRatioBased Sampler - had a sampling ratio of 1 to every 10,000 spans it COULD return - `"TraceIdRatioBased{0.000100}"` as its description. - -TODO: Add details about how the `TraceIdRatioBased` is implemented as a function -of the `TraceID`. [#1413](https://github.com/open-telemetry/opentelemetry-specification/issues/1413) - -##### Requirements for `TraceIdRatioBased` sampler algorithm - -* The sampling algorithm MUST be deterministic. A trace identified by a given - `TraceId` is sampled or not independent of language, time, etc. To achieve this, - implementations MUST use a deterministic hash of the `TraceId` when computing - the sampling decision. By ensuring this, running the sampler on any child `Span` - will produce the same decision. -* A `TraceIdRatioBased` sampler with a given sampling rate MUST also sample all - traces that any `TraceIdRatioBased` sampler with a lower sampling rate would - sample. This is important when a backend system may want to run with a higher - sampling rate than the frontend system, this way all frontend traces will - still be sampled and extra traces will be sampled on the backend only. -* **WARNING:** Since the exact algorithm is not specified yet (see TODO above), - there will probably be changes to it in any language SDK once it is, which - would break code that relies on the algorithm results. - Only the configuration and creation APIs can be considered stable. - It is recommended to use this sampler algorithm only for root spans - (in combination with [`ParentBased`](#parentbased)) because different language - SDKs or even different versions of the same language SDKs may produce inconsistent - results for the same input. +**Status**: [Development](../document-status.md) + +The `TraceIdRatioBased` sampler implements simple, ratio-based probability sampling using randomness features specified in the [W3C Trace Context Level 2][W3CCONTEXTMAIN] Candidate Recommendation. +OpenTelemetry follows W3C Trace Context Level 2, which specifies 56 bits of randomness, +[specifying how to make consistent probability sampling decisions using 56 bits of randomness][CONSISTENTSAMPLING]. + +The `TraceIdRatioBased` sampler MUST ignore the parent `SampledFlag`. +For respecting the parent `SampledFlag`, see the `ParentBased` sampler specified below. + +Note that the "ratio-based" part of this Sampler's name implies that +it makes a probability decision directly from the TraceID, even though +it was not originally specified in an exact way. In the present +specification, the Sampler decision is more nuanced: only a portion of +the identifier is used, after checking whether the OpenTelemetry +TraceState field contains an explicit trace randomness value. + +[W3CCONTEXTMAIN]: https://www.w3.org/TR/trace-context-2 + +##### `TraceIdRatioBased` sampler configuration + +The `TraceIdRatioBased` sampler is typically configured using a 32-bit or 64-bit floating point number to express the sampling ratio. +The minimum valid sampling ratio is `2^-56`, and the maximum valid sampling ratio is 1.0. +From an input sampling ratio, a rejection threshold value is calculated; see [consistent-probability sampler requirements][CONSISTENTSAMPLING] for details on converting sampling ratios into thresholds with variable precision. + +[CONSISTENTSAMPLING]: ./tracestate-probability-sampling.md + +##### `TraceIdRatioBased` sampler algorithm + +Given a Sampler configured with a sampling threshold `T` and Context with randomness value `R` (typically, the 7 rightmost bytes of the trace ID), when `ShouldSample()` is called, it uses the expression `R >= T` to decide whether to return `RECORD_AND_SAMPLE` or `DROP`. + +* If randomness value (R) is greater or equal to the rejection threshold (T), meaning when (R >= T), return `RECORD_AND_SAMPLE`, otherwise, return `DROP`. +* When (R >= T), the OpenTelemetry TraceState SHOULD be modified to include the key-value `th:T` for rejection threshold value (T), as specified for the [OpenTelemetry TraceState `th` sub-key][TRACESTATEHANDLING]. + +[TRACESTATEHANDLING]: ./tracestate-handling.md#sampling-threshold-value-th + +##### `TraceIdRatioBased` sampler description + +The `TraceIdRatioBased` GetDescription MUST return a string of the form `"TraceIdRatioBased{RATIO}"` +with `RATIO` replaced with the Sampler instance's trace sampling ratio +represented as a decimal number. The precision of the number SHOULD follow +implementation language standards and SHOULD be high enough to identify when +Samplers have different ratios. For example, if a TraceIdRatioBased Sampler +had a sampling ratio of 1 to every 10,000 spans it could return +`"TraceIdRatioBased{0.000100}"` as its description. + +##### `TraceIdRatioBased` sampler compatibility warning + +This specification has been revised from the original +`TraceIdRatioBased` Sampler definition. The present definition for +`TraceIdRatioBased` uses a new definition for trace randomness, where +unless an explicit trace randomness value is set in the OpenTelemetry +TraceState `rv` sub-key, Samplers are meant to presume that TraceIDs +contain the necessary 56 bits of randomness. + +When a TraceIdRatioBased Sampler makes a decision for a non-root Span +based on TraceID randomness, there is a possibility that the TraceID +was in fact generated by an older SDK, unaware of this specification. +The Trace random flag lets us disambiguate these two cases. This flag +propagates information to let TraceIdRatioBased Samplers confirm that +TraceIDs are random, however this requires W3C Trace Context Level 2 +to be supported by every Trace SDK that has handled the context. + +When a TraceIdRatioBased Sampler makes a decision for a non-root Span +using TraceID randomness, but the Trace random flag was not set, the +SDK SHOULD issue a one-time warning statement in its log with a +compatibility warning. As an example of this compatibility warning: + +``` +WARNING: The TraceIdRatioBased sampler is presuming TraceIDs are random +and expects the Trace random flag to be set in confirmation. Please +upgrade your caller(s) to use W3C Trace Context Level 2. +``` #### ParentBased diff --git a/specification/trace/tracestate-handling.md b/specification/trace/tracestate-handling.md index b8486abcd54..671465cb6e2 100644 --- a/specification/trace/tracestate-handling.md +++ b/specification/trace/tracestate-handling.md @@ -6,6 +6,21 @@ linkTitle: TraceState **Status**: [Development](../document-status.md) +
+Table of Contents + + + +- [Key](#key) +- [Value](#value) +- [Setting values](#setting-values) +- [Pre-defined OpenTelemetry sub-keys](#pre-defined-opentelemetry-sub-keys) + * [Sampling threshold value `th`](#sampling-threshold-value-th) + + + +
+ In alignment to the [TraceContext](https://www.w3.org/TR/trace-context/) specification, this section uses the Augmented Backus-Naur Form (ABNF) notation of [RFC5234](https://www.w3.org/TR/trace-context/#bib-rfc5234), including the DIGIT rule in that document. @@ -83,3 +98,51 @@ if ok { // traceState was not updated. } ``` + +## Pre-defined OpenTelemetry sub-keys + +The following values have been defined by OpenTelemetry. + +### Sampling threshold value `th` + +The OpenTelemetry TraceState `th` sub-key defines a sampling threshold, which conveys effective sampling probability. +Valid values of the `th` sub-fields include between 1 and 14 lowercase hexadecimal digits. + +``` +hexdigit = DIGIT ; a-f +``` + +To decode the threshold from the OpenTelemetry TraceState `th` value, first extend the value with trailing zeros to make 14 digits. +Then, parse the 14-digit value as a 56-bit unsigned hexadecimal number, yielding a rejection threshold. + +OpenTelemetry defines consistent sampling in terms of a 56-bit trace randomness value compared with the 56-bit rejection threshold. +When the randomness value is less than the rejection threshold, the span is not sampled. + +The threshold value `0` indicates that no spans are being rejected, corresponding with 100% sampling. +For example, the following TraceState value identifies a trace with 100% sampling: + +``` +tracestate: ot=th:0 +``` + +To calculate sampling probability from the rejection threshold, define a constant `MaxAdjustedCount` equal to 2^56, the number of distinct 56-bit values. +The sampling probability is defined: + +``` +Probability = (MaxAdjustedCount - Threshold) / MaxAdjustedCount +``` + +Threshold can be calculated from Probability: + +``` +Threshold = MaxAdjustedCount * (1 - Probability) +``` + +In sampling, the term _adjusted count_ refers to the effective number of items represented by a sampled item of telemetry. +The adjusted count of a span is the inverse of its sampling probability and can be derived from the threshold as follows. + +``` +AdjustedCount = MaxAdjustedCount / (MaxAdjustedCount - Threshold) +``` + +As an example, 25% probability sampling corresponds with adjusted count 4 and threshold `c`. diff --git a/specification/trace/tracestate-probability-sampling.md b/specification/trace/tracestate-probability-sampling.md index 8a6d769a9ef..79579621b7a 100644 --- a/specification/trace/tracestate-probability-sampling.md +++ b/specification/trace/tracestate-probability-sampling.md @@ -1,11 +1,256 @@ -# TraceState Probability Sampling +# TraceState: Probability Sampling **Status**: [Development](../document-status.md) -The contents of the [experimental probability sampling specification](./tracestate-probability-sampling-experimental.md) have been saved for future reference. +
+Table of Contents -This document is being updated with the specification finalized in [OTEP 235](https://github.com/open-telemetry/oteps/blob/main/text/trace/0235-sampling-threshold-in-trace-state.md), see [this tracking issue](https://github.com/open-telemetry/opentelemetry-specification/issues/1413). + + +- [Overview](#overview) +- [Definitions](#definitions) + * [Sampling Probability](#sampling-probability) + * [Consistent Sampling Decision](#consistent-sampling-decision) + * [Rejection Threshold (T)](#rejection-threshold-t) + * [Random Value (R)](#random-value-r) + * [Consistent Sampling Decision Approach](#consistent-sampling-decision-approach) +- [Explanation](#explanation) +- [Sampler behavior for initializing and updating T and R values](#sampler-behavior-for-initializing-and-updating-t-and-r-values) + * [Head samplers](#head-samplers) + * [Downstream samplers](#downstream-samplers) + * [Migration to consistent probability samplers](#migration-to-consistent-probability-samplers) +- [Algorithms](#algorithms) + * [Converting floating-point probability to threshold value](#converting-floating-point-probability-to-threshold-value) + * [Converting integer threshold to a `th`-value](#converting-integer-threshold-to-a-th-value) + * [Testing randomness vs threshold](#testing-randomness-vs-threshold) + * [Converting threshold to a sampling probability](#converting-threshold-to-a-sampling-probability) + * [Converting threshold to an adjusted count (sampling rate)](#converting-threshold-to-an-adjusted-count-sampling-rate) + + + +
+ +## Overview + +Sampling is an important lever to reduce the costs associated with collecting and processing telemetry data. It enables you to choose a representative set of items from an overall population. + +There are two key aspects for sampling of tracing data. The first is that sampling decisions can be made independently for *each* span in a trace. The second is that sampling decisions can be made at multiple points in the telemetry pipeline. For example, the sampling decision for a span at span creation time could have been to **keep** that span, while the downstream sampling decision for the *same* span at a later stage (say in an external process in the data collection pipeline) could be to **drop** it. + +For each of the above aspects, if we don't make **consistent** sampling decisions, we will end up with traces that are unusable and do not contain a coherent set of spans, because of the independent sampling decisions. Instead, we want sampling decisions to be made in a **consistent** manner so that we can effectively reason about a trace. + +This specification describes a mechanism to achieve such consistent sampling decisions using a mechanism called **Consistent Probability Sampling**. To achieve this, it uses two key building blocks. The first is a common source of randomness (R) that is available to all participants, which includes a set of tracers and collectors. This can be either a custom value (called `rv`) or taken from the trailing 7 bytes of the TraceID. The second is a concept of a rejection threshold (T). This is derived directly from a participant's sampling rate. This proposal describes how these two values should be propagated and how participants should use them to make sampling decisions. + +For more details about this specification, see [OTEP 235](https://github.com/open-telemetry/oteps/blob/main/text/trace/0235-sampling-threshold-in-trace-state.md). + +## Definitions + +### Sampling Probability + +Sampling probability is the likelihood that a span will be *kept*. Each participant can choose a different sampling probability for each span. For example, if the sampling probability is 0.25, around 25% of the spans will be kept. + +Sampling probability is valid in the range 2^-56 through 1. The value 56 appearing in this expression corresponds with 7 bytes of randomness (i.e., 56 bits) which are specified for W3C Trace Context Level 2 TraceIDs. Note that the zero value is not defined and that "never" sampling is not a form of probability sampling. + +### Consistent Sampling Decision + +A consistent sampling decision means that a positive sampling decision made for a particular span with probability p1 necessarily implies a positive sampling decision for any span belonging to the same trace if it is made with probability p2 >= p1. + +### Rejection Threshold (T) + +This is a 56-bit value directly derived from the sampling probability. One way to think about this is that this is the number of spans that would be *dropped* out of 2^56 considered spans. [This is an alternative to the `p` value in the previous specification. The `p` value is limited to powers of two, while this supports a large range of values.](./tracestate-probability-sampling-experimental.md) + +You can derive the rejection threshold from the sampling probability as follows: + +``` +Rejection_Threshold = (1 - Sampling_Probability) * 2^56. +``` + +For example, if the sampling probability is 100% (keep all spans), the rejection threshold is 0. + +Similarly, if the sampling probability is 1% (drop 99% of spans), the rejection threshold with 5 digits of precision would be (1-0.01) * 2^56 ≈ 71337018784743424 = 0xfd70a400000000. + +We refer to this rejection threshold conceptually as `T`. We represent it using the OpenTelemetry TraceState key `th`, where the value is propagated and also stored with each span. In the example above, the `th` key has `fd70a4` as the value, because trailing zeros are removed. + +See [tracestate handling](./tracestate-handling.md#sampling-threshold-value-th) for details about encoding threshold values. + +### Random Value (R) + +A common random value (that is known or propagated to all participants) is the main ingredient that enables consistent probability sampling. Each participant can compare this value (R) with their rejection threshold (T) to make a consistent sampling decision across an entire trace (or even across a group of traces). + +This proposal supports two sources of randomness: + +- **An explicit source of randomness**: OpenTelemetry supports a *random* (or pseudo-random) 56-bit value known as explicit trace randomness. This can be propagated through the OpenTelemetry TraceState `rv` sub-key and is stored in the Span's TraceState field. +- **Using TraceID as a source of randomness**: OpenTelemetry supports using the [least-significant 56 bits of the TraceID as the source of randomness, as specified in W3C Trace Context Level 2][W3CCONTEXTTRACEID]. This can be done if the root Span's Trace SDK knows that the TraceID has been generated in a random or pseudo-random manner. + +[W3CCONTEXTTRACEID]: https://www.w3.org/TR/trace-context-2/#randomness-of-trace-id + +See [tracestate handling](./tracestate-handling.md#sampling-randomness-value-rv) for details about encoding randomness values. + +### Consistent Sampling Decision Approach + +Given the above building blocks, let's look at how a participant can make consistent sampling decisions. For this, two values MUST be present in the `SpanContext`: + +1. The common source of randomness: the 56-bit `R` value. +2. The rejection threshold: the 56-bit `T` value. + +If `R` >= `T`, *keep* the span, else *drop* the span. + +`T` represents the maximum threshold that was applied in all previous consistent sampling stages. If the current sampling stage applies a greater threshold value than any stage before, it MUST update (increase) the threshold correspondingly by re-encoding the OpenTelemetry TraceState value. + +## Explanation + +## Sampler behavior for initializing and updating T and R values + +There are two categories of samplers: + +- **Head samplers:** Implementations of [`Sampler`](./sdk.md#sampler), called by a `Tracer` during span creation for both root and child spans. +- **Downstream samplers:** Any component that, given an ended Span, decides whether to *drop* it or *keep* it (by forwarding it to the next component in the pipeline). This category is also known as "collection path samplers" or "sampling processors". Note that *Tail samplers* are a special class of downstream samplers that buffer spans of a trace and make a sampling decision for the trace as a whole using data from any span in the buffered trace. + +This section defines the behavior for these two categories of samplers. + +### Head samplers + +See [SDK requirements for trace randomness](./sdk.md#sampling-requirements), which covers potentially inserting explicit trace randomness using the OpenTelemetry TraceState `rv` sub-key. + +A head Sampler is responsible for computing the `th` value in a new span's [OpenTelemetry TraceState](./tracestate-handling.md#tracestate-handling). The main inputs to that computation include the parent context's TraceState and the TraceID. + +When a span is sampled by in accordance with this specification, the output TraceState SHOULD be set to convey probability sampling: + +- The `th` key MUST be defined with a threshold value corresponding to the sampling probability the sampler used. +- If trace randomness was derived from a OpenTelemetry TraceState `rv` sub-key value, the same `rv` value MUST be defined and equal to the incoming OpenTelemetry TraceState `rv` sub-key value. + +### Downstream samplers + +A downstream sampler, in contrast, may output a given ended Span with a *modified* trace state, complying with following rules: + +- If the chosen sampling probability is 1, the sampler MUST NOT modify an existing `th` sub-key value, nor set a `th` sub-key value. +- Otherwise, the chosen sampling probability is in `(0, 1)`. In this case the sampler MUST output the span with a `th` equal to `max(input th, chosen th)`. In other words, `th` MUST NOT be decreased (as it is not possible to retroactively adjust an earlier stage's sampling probability), and it MUST be increased if a lower sampling probability was used. This case represents the common case where a downstream sampler is reducing span throughput in the system. + +### Migration to consistent probability samplers + +The OpenTelemetry specification for TraceIdRatioBased samplers was not completed until after the SDK specification was declared stable, and the exact behavior of that sampler was left unspecified. The `th` and `rv` sub-keys defined in the OpenTelemetry TraceState now address this behavior specifically. + +As the OpenTelemetry TraceIdRatioBased sampler changes definition, users must consider how to avoid incomplete traces due to inconsistent sampling during the transition between old and new logic. + +The original TraceIdRatioBased sampler specification gave a workaround for the underspecified behavior, that it was safe to use for root spans: "It is recommended to use this sampler algorithm only for root spans (in combination with [`ParentBased`](./sdk.md#parentbased)) because different language SDKs or even different versions of the same language SDKs may produce inconsistent results for the same input." + +To avoid inconsistency during this transition, users SHOULD follow +this guidance until all Trace SDKs in a system have been upgraded to +modern Trace randomness requirements based on W3C Trace Context +Level 2. +Users can verify that all Trace SDKs have been upgraded when all Spans +in their system have the Trace random flag set (in Span flags). +To assist with this migration, the TraceIdRatioBased Sampler issues a +warning statement the first time it presumes TraceID randomness for a +Context where the Trace random flag is not set. + +## Algorithms + +The `th` and `rv` values may be represented and manipulated in a variety of forms depending on the capabilities of the processor and needs of the implementation. As 56-bit values, they are compatible with byte arrays and 64-bit integers, and can also be manipulated with 64-bit floating point with a truly negligible loss of precision. + +The following examples are in Golang and Python3. They are intended as examples only for clarity, and not as a suggested implementation. + +### Converting floating-point probability to threshold value + +Threshold values are encoded with trailing zeros removed, which allows for variable precision. This can be accomplished by rounding, and there are several practical ways to do this with built-in string formatting libraries. + +With up to 56 bits of precision available, implementations that use built-in floating point number support will be limited by the precision of the underlying number support. One way to encode thresholds uses the IEEE 754-2008-standard hexadecimal floating point representation as a simple solution. For example, in Golang, + +```go +// ProbabilityToThresholdWithPrecision assumes the probability value is in the range +// [0x1p-56, 1] and precision is in the range [1, 14]. +func ProbabilityToThresholdWithPrecision(probability float64, precision int) string { + if probability == 1 { + // Special case + return "0" + } + // Raise precision by the number of leading 'f' digits. + _, expF := math.Frexp(probability) + precision = min(14, precision+expF/-4) + + // Change the probability to rejection probability, with range [0, 1), + // translate rejection probability by +1, into range [1, 2). + // Format the significand of this expression as hexadecimal floating point + asHex := strconv.FormatFloat(2-probability, 'x', precision, 64) + + // Strip the leading "0x1.", use the requested number of digits. + // Strip additional trailing zeros. + digits := asHex[4 : 4+precision] + return strings.TrimRight(digits, "0") +} +``` + +Note the use of `math.Frexp(probability)` used to adjust precision +using the base-2 exponent of the probability argument. This makes the +configured precision apply to the significant digits of the threshold +for probabilities near zero. Note that there is not a symmetrical +adjustment made for values near unit probability, as we do not believe +there is a practical use for sampling very precisely near 100%. + +To translate directly from floating point probability into a 56-bit unsigned integer representation using `math.Round()` and shift operations, see the [OpenTelemetry Collector-Contrib `pkg/sampling` package][PKGSAMPLING] package. This package demonstrates how to directly calculate integer thresholds from probabilities. + +[PKGSAMPLING]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/sampling/README.md + +OpenTelemetry SDKs are recommended to use 4 digits of precision by default. The following table shows values computed by the method above for 1-in-N probability sampling, with precision 3, 4, and 5. + + +| 1-in-N | Input probability | Threshold (precision 3, 4, 5) | Actual probability (precision 3, 4, 5) | Exact Adjusted Count (precision 3, 4, 5) | +|---------|--------------------|------------------------------------|------------------------------------------------------------------------------|-----------------------------------------------------------------------| +| 1 | 1 | 0
0
0 | 1
1
1 | 1
1
1 | +| 2 | 0.5 | 8
8
8 | 0.5
0.5
0.5 | 2
2
2 | +| 3 | 0.3333333333333333 | aab
aaab
aaaab | 0.333251953125
0.3333282470703125
0.33333301544189453 | 3.0007326007326007
3.00004577706569
3.0000028610256777 | +| 4 | 0.25 | c
c
c | 0.25
0.25
0.25 | 4
4
4 | +| 5 | 0.2 | ccd
cccd
ccccd | 0.199951171875
0.1999969482421875
0.19999980926513672 | 5.001221001221001
5.0000762951094835
5.0000047683761295 | +| 8 | 0.125 | e
e
e | 0.125
0.125
0.125 | 8
8
8 | +| 10 | 0.1 | e66
e666
e6666 | 0.10009765625
0.100006103515625
0.10000038146972656 | 9.990243902439024
9.99938968568813
9.999961853172863 | +| 16 | 0.0625 | f
f
f | 0.0625
0.0625
0.0625 | 16
16
16 | +| 100 | 0.01 | fd71
fd70a
fd70a4 | 0.0099945068359375
0.010000228881835938
0.009999990463256836 | 100.05496183206107
99.99771123402633
100.00009536752259 | +| 1000 | 0.001 | ffbe7
ffbe77
ffbe76d | 0.0010004043579101562
0.0009999871253967285
0.000999998301267624 | 999.5958055290753
1000.012874769029
1000.0016987352618 | +| 10000 | 0.0001 | fff972
fff9724
fff97247 | 0.00010001659393310547
0.00010000169277191162
0.00010000006295740604 | 9998.340882002383
9999.830725674266
9999.99370426336 | +| 100000 | 0.00001 | ffff584
ffff583a
ffff583a5 | 9.998679161071777e-06
1.00000761449337e-05
1.0000003385357559e-05 | 100013.21013412817
99999.238556461
99999.96614643588 | +| 1000000 | 0.000001 | ffffef4
ffffef39
ffffef391 | 9.98377799987793e-07
1.00000761449337e-06
9.999930625781417e-07 | 1.0016248358208955e+06
999992.38556461
1.0000069374699865e+06 | + +### Converting integer threshold to a `th`-value + +To convert a 56-bit integer threshold value to the t-value representation, emit it as a hexadecimal value (without a leading '0x'), optionally with trailing zeros omitted: + +```py +if tvalue == 0: + add_otel_trace_state('tv:0') +else: + h = hex(tvalue).rstrip('0') + # remove leading 0x + add_otel_trace_state('tv:'+h[2:]) +``` + +### Testing randomness vs threshold + +Given randomness and threshold as 64-bit integers, a sample should be taken if randomness is greater than or equal to the threshold. + +``` +shouldSample = (randomness >= threshold) +``` + +### Converting threshold to a sampling probability + +The sampling probability is a value from 0.0 to 1.0, which can be calculated using floating point by dividing by 2^56: + +```py +# embedded _ in numbers for clarity (permitted by Python3) +maxth = 0x100_0000_0000_0000 # 2^56 +prob = float(maxth - threshold) / maxth +``` + +### Converting threshold to an adjusted count (sampling rate) + +The adjusted count indicates the approximate quantity of items from the population that this sample represents. It is equal to `1/probability`. + +```py +maxth = 0x100_0000_0000_0000 # 2^56 +adjCount = maxth / float(maxth - threshold) +``` + +Adjusted count is not defined for spans that were obtained via non-probabilistic sampling (a sampled span with no `th` value).