Documentation
¶
Index ¶
- Constants
- Variables
- func ThresholdGreater(a, b Threshold) bool
- func ThresholdLessThan(a, b Threshold) bool
- type KV
- type OpenTelemetryTraceState
- func (otts *OpenTelemetryTraceState) AdjustedCount() float64
- func (otts *OpenTelemetryTraceState) ClearRValue()
- func (otts *OpenTelemetryTraceState) ClearTValue()
- func (cts OpenTelemetryTraceState) ExtraValues() []KV
- func (otts *OpenTelemetryTraceState) HasAnyValue() bool
- func (otts *OpenTelemetryTraceState) RValue() string
- func (otts *OpenTelemetryTraceState) RValueRandomness() (Randomness, bool)
- func (otts *OpenTelemetryTraceState) Serialize(w io.StringWriter) error
- func (otts *OpenTelemetryTraceState) SetRValue(randomness Randomness)
- func (otts *OpenTelemetryTraceState) TValue() string
- func (otts *OpenTelemetryTraceState) TValueThreshold() (Threshold, bool)
- func (otts *OpenTelemetryTraceState) UpdateTValueWithSampling(sampledThreshold Threshold) error
- type Randomness
- type Threshold
- type W3CTraceState
Examples ¶
- OpenTelemetryTraceState.AdjustedCount
- ProbabilityToThreshold (Limitedprecision)
- ProbabilityToThreshold (Rounding)
- ProbabilityToThreshold (Verysmall)
- ProbabilityToThresholdWithPrecision
- RValueToRandomness
- TValueToThreshold
- Threshold.ShouldSample
- Threshold.ShouldSample (Traceid)
- TraceIDToRandomness
- W3CTraceState
- W3CTraceState.Serialize
Constants ¶
const ( // MaxAdjustedCount is 2^56 i.e. 0x100000000000000 i.e., 1<<56. MaxAdjustedCount uint64 = 1 << 56 // NumHexDigits is the number of hex digits equalling 56 bits. // This is the limit of sampling precision. NumHexDigits = 56 / hexBits )
const MinSamplingProbability = 1.0 / float64(MaxAdjustedCount)
MinSamplingProbability is the smallest representable probability and is the inverse of MaxAdjustedCount.
Variables ¶
var ( // ErrTValueSize is returned for t-values longer than NumHexDigits hex digits. ErrTValueSize = errors.New("t-value exceeds 14 hex digits") // ErrEmptyTValue indicates no t-value was found, i.e., no threshold available. ErrTValueEmpty = errors.New("t-value is empty") // AlwaysSampleThreshold represents 100% sampling. AlwaysSampleThreshold = Threshold{/* contains filtered or unexported fields */} // NeverSampledThreshold is a threshold value that will always not sample. // The TValue() corresponding with this threshold is an empty string. NeverSampleThreshold = Threshold{/* contains filtered or unexported fields */} )
var AllProbabilitiesRandomness = Randomness{/* contains filtered or unexported fields */}
AllProbabilitiesRandomness is sampled at all probabilities.
var ( // ErrInconsistentSampling is returned when a sampler update // is illogical, indicating that the tracestate was not // modified. Preferably, Samplers will avoid seeing this // error by using a ThresholdGreater() test, which allows them // to report a more clear error to the user. For example, if // data arrives sampled at 1/100 and an equalizing sampler is // configured for 1/2 sampling, the Sampler may detect the // illogical condition itself using ThresholdGreater and skip // the call to UpdateTValueWithSampling, which will have no // effect and return this error. How a sampler decides to // handle this condition is up to the sampler: for example the // equalizing sampler can decide to pass through a span // indicating 1/100 sampling or it can reject the span. ErrInconsistentSampling = errors.New("cannot raise existing sampling probability") )
var ErrProbabilityRange = errors.New("sampling probability out of the range [1/MaxAdjustedCount, 1]")
ErrProbabilityRange is returned when a value should be in the range [1/MaxAdjustedCount, 1].
var ErrRValueSize = errors.New("r-value must have 14 hex digits")
ErrRValueSize is returned by RValueToRandomess in case of unexpected size.
var ( // ErrTraceStateSize is returned when a TraceState is over its // size limit, as specified by W3C. ErrTraceStateSize = errors.New("invalid tracestate size") )
Functions ¶
func ThresholdGreater ¶
ThresholdGreater allows direct comparison of Threshold values. Greater thresholds equate with smaller sampling probabilities.
func ThresholdLessThan ¶
ThresholdLessThan allows direct comparison of Threshold values. Smaller thresholds equate with greater sampling probabilities.
Types ¶
type OpenTelemetryTraceState ¶
type OpenTelemetryTraceState struct {
// contains filtered or unexported fields
}
OpenTelemetryTraceState represents the `ot` section of the W3C tracestate which is specified generically in https://opentelemetry.io/docs/specs/otel/trace/tracestate-handling/.
OpenTelemetry defines two specific values that convey sampling probability, known as T-Value (with "th", for threshold), R-Value (with key "rv", for random value), and extra values.
func NewOpenTelemetryTraceState ¶
func NewOpenTelemetryTraceState(input string) (OpenTelemetryTraceState, error)
NewOpenTelemetryTraceState returns a parsed representation of the OpenTelemetry tracestate section. Errors indicate an invalid tracestate was received.
func (*OpenTelemetryTraceState) AdjustedCount ¶
func (otts *OpenTelemetryTraceState) AdjustedCount() float64
AdjustedCount returns the adjusted count for this item. If the TValue string is empty, this returns 0, otherwise returns Threshold.AdjustedCount().
Example ¶
ExampleOpenTelemetryTraceState_AdjustedCount shows how to access the adjusted count for a sampled context when it has non-zero probability.
w3c, err := NewW3CTraceState("ot=th:c") if err != nil { panic(err) } ot := w3c.OTelValue() fmt.Printf("Adjusted count for T-value %q: %f", ot.TValue(), ot.AdjustedCount())
Output: Adjusted count for T-value "c": 4.000000
func (*OpenTelemetryTraceState) ClearRValue ¶
func (otts *OpenTelemetryTraceState) ClearRValue()
ClearRValue unsets explicit randomness.
func (*OpenTelemetryTraceState) ClearTValue ¶
func (otts *OpenTelemetryTraceState) ClearTValue()
ClearTValue is used to unset TValue, for use in cases where it is inconsistent on arrival.
func (OpenTelemetryTraceState) ExtraValues ¶
func (cts OpenTelemetryTraceState) ExtraValues() []KV
ExtraValues returns additional values are carried in this tracestate object (W3C or OpenTelemetry).
func (*OpenTelemetryTraceState) HasAnyValue ¶
func (otts *OpenTelemetryTraceState) HasAnyValue() bool
HasAnyValue returns true if there are any fields in this tracestate, including any extra values.
func (*OpenTelemetryTraceState) RValue ¶
func (otts *OpenTelemetryTraceState) RValue() string
RValue returns the R-value (key: "rv") as a string or empty if there is no R-value set.
func (*OpenTelemetryTraceState) RValueRandomness ¶
func (otts *OpenTelemetryTraceState) RValueRandomness() (Randomness, bool)
RValueRandomness returns the randomness object corresponding with RValue() and a boolean indicating whether the R-value is set.
func (*OpenTelemetryTraceState) Serialize ¶
func (otts *OpenTelemetryTraceState) Serialize(w io.StringWriter) error
Serialize encodes this TraceState object.
func (*OpenTelemetryTraceState) SetRValue ¶
func (otts *OpenTelemetryTraceState) SetRValue(randomness Randomness)
SetRValue establishes explicit randomness for this TraceState.
func (*OpenTelemetryTraceState) TValue ¶
func (otts *OpenTelemetryTraceState) TValue() string
TValue returns the T-value (key: "th") as a string or empty if there is no T-value set.
func (*OpenTelemetryTraceState) TValueThreshold ¶
func (otts *OpenTelemetryTraceState) TValueThreshold() (Threshold, bool)
TValueThreshold returns the threshold object corresponding with TValue() and a boolean (equal to len(TValue()) != 0 indicating whether the T-value is valid.
func (*OpenTelemetryTraceState) UpdateTValueWithSampling ¶
func (otts *OpenTelemetryTraceState) UpdateTValueWithSampling(sampledThreshold Threshold) error
UpdateTValueWithSampling modifies the TValue of this object, which changes its adjusted count. It is not logical to modify a sampling probability in the direction of larger probability. This prevents accidental loss of adjusted count.
If the change of TValue leads to inconsistency, an error is returned.
type Randomness ¶
type Randomness struct {
// contains filtered or unexported fields
}
Randomness may be derived from R-value or TraceID.
Randomness contains 56 bits of randomness, derived in one of two ways, see: https://www.w3.org/TR/trace-context-2/#randomness-of-trace-id
func RValueToRandomness ¶
func RValueToRandomness(s string) (Randomness, error)
RValueToRandomness parses NumHexDigits hex bytes into a Randomness.
Example ¶
// Any 14 hex digits is a valid R-value. const exampleRvalue = "d29d6a7215ced0" // This converts to the internal unsigned integer representation. rnd, _ := RValueToRandomness(exampleRvalue) // The result prints the same as the input. fmt.Printf("RValueToRandomness(%q).RValue() = %s", exampleRvalue, rnd.RValue())
Output: RValueToRandomness("d29d6a7215ced0").RValue() = d29d6a7215ced0
func TraceIDToRandomness ¶
func TraceIDToRandomness(id pcommon.TraceID) Randomness
TraceIDToRandomness returns randomness from a TraceID (assumes the traceparent random flag was set).
Example ¶
// TraceID represented in hex as "abababababababababd29d6a7215ced0" var exampleTid = pcommon.TraceID{ // 9 meaningless bytes 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, // 7 bytes randomness 0xd2, 0x9d, 0x6a, 0x72, 0x15, 0xce, 0xd0, } rnd := TraceIDToRandomness(exampleTid) fmt.Printf("TraceIDToRandomness(%q).RValue() = %s", exampleTid, rnd.RValue())
Output: TraceIDToRandomness("abababababababababd29d6a7215ced0").RValue() = d29d6a7215ced0
func UnsignedToRandomness ¶ added in v0.98.0
func UnsignedToRandomness(x uint64) (Randomness, error)
UnsignedToRandomness constructs a randomness using 56 random bits of unsigned number. If the input is out of range, an invalid value will be returned with an error.
func (Randomness) RValue ¶
func (rnd Randomness) RValue() string
RValue formats the r-value encoding.
func (Randomness) Unsigned ¶ added in v0.98.0
func (rnd Randomness) Unsigned() uint64
Unsigned returns the unsigned representation of the random value. Items of data SHOULD be sampled when:
Threshold.Unsigned() <= // Randomness.Unsigned().
type Threshold ¶
type Threshold struct {
// contains filtered or unexported fields
}
Threshold represents an exact sampling probability using 56 bits of precision. A Threshold expresses the number of spans, out of 2**56, that are rejected.
These 56 bits are compared against 56 bits of randomness, either extracted from an R-value or a TraceID having the W3C-specified randomness bit set.
Because Thresholds store 56 bits of information and floating point values store 52 bits of significand, some conversions between Threshold and probability values are lossy. The kinds of loss that occur depend on where in the probability scale it happens, as the step between adjacent floating point values adjusts with the exponent.
func ProbabilityToThreshold ¶
ProbabilityToThreshold converts a probability to a Threshold. It returns an error when the probability is out-of-range.
Example (Limitedprecision) ¶
ExampleProbabilityToThreshold_limitedprecision demonstrates the gap between Threshold values and probability values is not equal, clarifying which conversions are lossy.
next := func(x float64, n int) float64 { for ; n < 0; n++ { x = math.Nextafter(x, 0) } return x } // At probability 50% or above, only 52 bits of precision are // available for floating point representation. // // In the range 1/2 to 1: 52 bits of precision are available; 4 trailing zero bits; // In the range 1/4 to 1/2: 52 bits of precision are available; 3 trailing zero bits; // In the range 1/8 to 1/4: 52 bits of precision are available; 2 trailing zero bits; // In the range 1/16 to 1/8: 52 bits of precision are available; 1 trailing zero bits; // Probabilties less than 1/16: 51 bits of precision are available // Probabilties less than 1/32: 50 bits of precision are available. // ... // Probabilties less than 0x1p-N: 55-N bits of precision are available. // ... // Probabilities less than 0x1p-55: 0 bits of precision. const large = 15.0 / 16 const half = 8.0 / 16 const quarter = 4.0 / 16 const eighth = 2.0 / 16 const small = 1.0 / 16 for _, prob := range []float64{ // Values from 1/2 to 15/16: last T-value digit always "8". next(large, 0), next(large, -1), next(large, -2), next(large, -3), 0, // Values from 1/4 to 1/2: last T-value digit always // "4", "8", or "c". next(half, 0), next(half, -1), next(half, -2), next(half, -3), 0, // Values from 1/8 to 1/4, last T-value digit can be any // even hex digit. next(quarter, 0), next(quarter, -1), next(quarter, -2), next(quarter, -3), 0, // Values from 1/16 to 1/8: Every adjacent probability // value maps to an exact Threshold. next(eighth, 0), next(eighth, -1), next(eighth, -2), next(eighth, -3), 0, // Values less than 1/16 demonstrate lossy behavior. // Here probability values can express more values // than Thresholds can, so multiple probability values // map to the same Threshold. Here, 1/16 and the next // descending floating point value both map to T-value // "f". next(small, 0), next(small, -1), next(small, -2), next(small, -3), } { if prob == 0 { fmt.Println("--") continue } tval, _ := ProbabilityToThreshold(prob) fmt.Println(tval.TValue()) }
Output: 1 10000000000008 1000000000001 10000000000018 -- 8 80000000000004 80000000000008 8000000000000c -- c c0000000000002 c0000000000004 c0000000000006 -- e e0000000000001 e0000000000002 e0000000000003 -- f f f0000000000001 f0000000000001
Example (Rounding) ¶
ExampleProbabilityToThreshold_rounding demonstrates that with full precision, the resulting t-value appears to round in an unexpected way.
// 1/3 sampling corresponds with a rejection threshold of (1 - 1/3). const exampleProb = 1.0 / 3.0 // 1/3 in decimal is the repeating fraction of 6 (0.333333), while in // hexadecimal it is the repeating fraction of a (0x0.555555). tval, _ := ProbabilityToThreshold(exampleProb) // Note the trailing hex "c" below, which does not match // intuition for a repeating pattern of hex "a" digits. Why // is the final digit not hex "b"? The reason it is hex "c" // is that ProbabilityToThreshold computes the number of spans // selected as a 56-bit integer using a 52-bit significand. // Because the fraction uses fewer bits than the threshold, // the last digit rounds down, with 0x55555555555554 spans // rejected out of 0x100000000000000. The subtraction of 0x4 // from 0x10 leads to a trailing hex "c". fmt.Println(tval.TValue())
Output: aaaaaaaaaaaaac
Example (Verysmall) ¶
ExampleProbabilityToThreshold_verysmall shows the smallest expressible sampling probability values.
for _, prob := range []float64{ MinSamplingProbability, // Skip 1 out of 2**56 0x2p-56, // Skip 2 out of 2**56 0x3p-56, // Skip 3 out of 2**56 0x4p-56, // Skip 4 out of 2**56 0x8p-56, // Skip 8 out of 2**56 0x10p-56, // Skip 0x10 out of 2**56 } { // Note that precision is automatically raised for // such small probabilities, because leading 'f' and // '0' digits are discounted. tval, _ := ProbabilityToThresholdWithPrecision(prob, 3) fmt.Println(tval.TValue()) }
Output: ffffffffffffff fffffffffffffe fffffffffffffd fffffffffffffc fffffffffffff8 fffffffffffff
func ProbabilityToThresholdWithPrecision ¶
ProbabilityToThresholdWithPrecision is like ProbabilityToThreshold with support for reduced precision. The `precision` argument determines how many significant hex digits will be used to encode the exact probability.
Example ¶
ExampleProbabilityToThresholdWithPrecision demonstrates how 1/3, 2/3, and 3/3 are encoded with precision 3. When working with arbitrary floating point values, it is recommended to use an explicit precision parameter so that T-values are both reasonably compact and accurate.
const divisor = 3.0 const precision = 3 for dividend := 1.0; dividend <= divisor; dividend++ { tval, _ := ProbabilityToThresholdWithPrecision(dividend/divisor, precision) fmt.Println(tval.TValue()) }
Output: aab 555 0
func TValueToThreshold ¶
TValueToThreshold returns a Threshold. Because TValue strings have trailing zeros omitted, this function performs the reverse.
Example ¶
ExampleTValueToThreshold demonstrates how to convert a T-value string to a Threshold value.
// "c" corresponds with rejecting 3/4 traces (or 0xc out of // 0x10), which is 25% sampling. const exampleTvalue = "c" tval, _ := TValueToThreshold(exampleTvalue) fmt.Printf("Probability(%q) = %f", exampleTvalue, tval.Probability())
Output: Probability("c") = 0.250000
func UnsignedToThreshold ¶ added in v0.98.0
UnsignedToThreshold constructs a threshold expressed in terms defined by number of rejections out of MaxAdjustedCount, which equals the number of randomness values.
func (Threshold) AdjustedCount ¶ added in v0.98.0
AdjustedCount returns the adjusted count for this item, which is the representativity of the item due to sampling, equal to the inverse of sampling probability. If the threshold equals NeverSampleThreshold, the item should not have been sampled, in which case the Adjusted count is zero.
This term is defined here: https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/
func (Threshold) Probability ¶
Probability is the sampling ratio in the range [MinSamplingProb, 1].
func (Threshold) ShouldSample ¶
func (th Threshold) ShouldSample(rnd Randomness) bool
ShouldSample returns true when the span passes this sampler's consistent sampling decision. The sampling decision can be expressed as a T <= R.
Example ¶
ExampleTValueToThreshold demonstrates how to calculate whether a Threshold, calculated from a T-value, should be sampled at a given probability.
const exampleTvalue = "c" const exampleRvalue = "d29d6a7215ced0" tval, _ := TValueToThreshold(exampleTvalue) rval, _ := RValueToRandomness(exampleRvalue) fmt.Printf("TValueToThreshold(%q).ShouldSample(RValueToRandomness(%q) = %v", tval.TValue(), rval.RValue(), tval.ShouldSample(rval))
Output: TValueToThreshold("c").ShouldSample(RValueToRandomness("d29d6a7215ced0") = true
Example (Traceid) ¶
ExampleTValueToThreshold_traceid demonstrates how to calculate whether a Threshold, calculated from a T-value, should be sampled at a given probability.
const exampleTvalue = "c" // The leading 9 bytes (18 hex digits) of the TraceID string // are not used, only the trailing 7 bytes (14 hex digits, // i.e., 56 bits) are used. Here, the dont-care digits are // set to 0xab and the R-value is "bd29d6a7215ced0". const exampleHexTraceID = "abababababababababd29d6a7215ced0" var tid pcommon.TraceID idbytes, _ := hex.DecodeString(exampleHexTraceID) copy(tid[:], idbytes) tval, _ := TValueToThreshold(exampleTvalue) rval := TraceIDToRandomness(tid) fmt.Printf("TValueToThreshold(%q).ShouldSample(TraceIDToRandomness(%q) = %v", tval.TValue(), exampleHexTraceID, tval.ShouldSample(rval))
Output: TValueToThreshold("c").ShouldSample(TraceIDToRandomness("abababababababababd29d6a7215ced0") = true
type W3CTraceState ¶
type W3CTraceState struct {
// contains filtered or unexported fields
}
W3CTraceState represents the a parsed W3C `tracestate` header.
This type receives and passes through `tracestate` fields defined by all vendors, while it parses and validates the OpenTelemetryTraceState field. After parsing the W3CTraceState, access the OpenTelemetry-defined fields using W3CTraceState.OTelValue.
Example ¶
ExampleW3CTraceState_Serialize shows how to parse and print a W3C tracestate.
// This tracestate value encodes two sections, "ot" from // OpenTelemetry and "zz" from a vendor. w3c, err := NewW3CTraceState("ot=th:c;rv:d29d6a7215ced0;pn:abc,zz=vendorcontent") if err != nil { panic(err) } ot := w3c.OTelValue() fmt.Println("T-Value:", ot.TValue()) fmt.Println("R-Value:", ot.RValue()) fmt.Println("OTel Extra:", ot.ExtraValues()) fmt.Println("Other Extra:", w3c.ExtraValues())
Output: T-Value: c R-Value: d29d6a7215ced0 OTel Extra: [{pn abc}] Other Extra: [{zz vendorcontent}]
func NewW3CTraceState ¶
func NewW3CTraceState(input string) (w3c W3CTraceState, _ error)
NewW3CTraceState parses a W3C trace state, with special attention to the embedded OpenTelemetry trace state field.
func (W3CTraceState) ExtraValues ¶
func (cts W3CTraceState) ExtraValues() []KV
ExtraValues returns additional values are carried in this tracestate object (W3C or OpenTelemetry).
func (*W3CTraceState) HasAnyValue ¶
func (w3c *W3CTraceState) HasAnyValue() bool
HasAnyValue indicates whether there are any values in this tracestate, including extra values.
func (*W3CTraceState) OTelValue ¶
func (w3c *W3CTraceState) OTelValue() *OpenTelemetryTraceState
OTelValue returns the OpenTelemetry tracestate value.
func (*W3CTraceState) Serialize ¶
func (w3c *W3CTraceState) Serialize(w io.StringWriter) error
Serialize encodes this tracestate object for use as a W3C tracestate header value.
Example ¶
ExampleW3CTraceState_Serialize shows how to modify and serialize a new W3C tracestate.
w3c, err := NewW3CTraceState("") if err != nil { panic(err) } // Suppose a parent context was unsampled, the child span has // been sampled at 25%. The child's context should carry the // T-value of "c", serialize as "ot=th:c". th, err := ProbabilityToThreshold(0.25) if err != nil { panic(err) } // The update uses both the Threshold and its encoded string // value, since in some code paths the Threshold will have // just been parsed from a T-value, and in other code paths // the T-value will be precalculated. err = w3c.OTelValue().UpdateTValueWithSampling(th) if err != nil { panic(err) } var buf strings.Builder err = w3c.Serialize(&buf) if err != nil { panic(err) } fmt.Println(buf.String())
Output: ot=th:c