33
44#include < stddef.h>
55#include < atomic>
6- #include < cmath>
76#include < cstdint>
87#include < map>
98#include < memory>
2120#include " opentelemetry/trace/trace_state.h"
2221#include " opentelemetry/version.h"
2322
23+ #include " ot_trace_state.h"
24+
2425namespace trace_api = opentelemetry::trace;
2526namespace nostd = opentelemetry::nostd;
2627
2728namespace
2829{
29- constexpr char kOtTraceStateKey [] = " ot" ;
30-
31- // Rejection threshold for a ratio of zero, 2^56: drops every span.
32- constexpr uint64_t kMaxThreshold = 1ULL << 56 ;
33-
34- /* *
35- * Converts a ratio in [0, 1] to a 56-bit rejection threshold.
36- */
37- uint64_t CalculateRejectionThreshold (double ratio) noexcept
30+ // Clamps ratio to [0, 1]. NaN and negatives map to 0 (never-sample).
31+ double ClampProbability (double ratio) noexcept
3832{
39- // The negated comparison also routes NaN to the never-sample threshold.
4033 if (!(ratio > 0.0 ))
41- return kMaxThreshold ;
42- if (ratio >= 1.0 )
43- return 0 ;
44- return kMaxThreshold -
45- static_cast <uint64_t >(std::llround (ratio * static_cast <double >(kMaxThreshold )));
34+ return 0.0 ;
35+ if (ratio > 1.0 )
36+ return 1.0 ;
37+ return ratio;
4638}
4739
4840bool ParseHex56 (nostd::string_view hex, uint64_t *value) noexcept
@@ -83,19 +75,6 @@ std::string EncodeThreshold(uint64_t threshold)
8375 return hex;
8476}
8577
86- uint64_t RandomnessFromTraceId (const trace_api::TraceId &trace_id) noexcept
87- {
88- static_assert (trace_api::TraceId::kSize >= 7 , " TraceID must be at least 7 bytes long." );
89-
90- const uint8_t *data = trace_id.Id ().data ();
91- uint64_t result = 0 ;
92- for (size_t i = trace_api::TraceId::kSize - 7 ; i < trace_api::TraceId::kSize ; ++i)
93- {
94- result = (result << 8 ) | data[i];
95- }
96- return result;
97- }
98-
9978// Returns true when the ot value carries a valid rv sub-key.
10079bool ExplicitRandomness (nostd::string_view ot_value, uint64_t *randomness) noexcept
10180{
@@ -154,14 +133,9 @@ namespace sdk
154133namespace trace
155134{
156135ProbabilitySampler::ProbabilitySampler (double ratio)
157- : threshold_(CalculateRejectionThreshold(ratio))
158- {
159- if (!(ratio > 0.0 ))
160- ratio = 0.0 ;
161- if (ratio > 1.0 )
162- ratio = 1.0 ;
163- description_ = " ProbabilitySampler{" + std::to_string (ratio) + " }" ;
164- }
136+ : description_(" ProbabilitySampler{" + std::to_string(ClampProbability(ratio)) + " }" ),
137+ threshold_ (CalculateThreshold(ClampProbability(ratio)))
138+ {}
165139
166140SamplingResult ProbabilitySampler::ShouldSample (
167141 const trace_api::SpanContext &parent_context,
@@ -171,31 +145,41 @@ SamplingResult ProbabilitySampler::ShouldSample(
171145 const opentelemetry::common::KeyValueIterable & /* attributes*/ ,
172146 const trace_api::SpanContextKeyValueIterable & /* links*/ ) noexcept
173147{
174- if (threshold_ == kMaxThreshold )
175- return {Decision::DROP , nullptr , {}};
176-
177148 auto parent_trace_state = parent_context.trace_state ();
178149 std::string ot_value;
179150 bool has_ot = parent_trace_state->Get (kOtTraceStateKey , ot_value);
180151
181- uint64_t randomness = 0 ;
182- if (!ExplicitRandomness (ot_value, &randomness) )
152+ bool drop = threshold_ == kMaxThreshold ;
153+ if (!drop )
183154 {
184- if (parent_context.IsValid () && !parent_context.trace_flags ().IsRandom ())
155+ uint64_t randomness = 0 ;
156+ if (!ExplicitRandomness (ot_value, &randomness))
185157 {
186- static std::atomic<bool > warned{false };
187- if (!warned.exchange (true ))
158+ if (parent_context.IsValid () && !parent_context.trace_flags ().IsRandom ())
188159 {
189- OTEL_INTERNAL_LOG_WARN (
190- " ProbabilitySampler presumes TraceID randomness, but the W3C random trace flag is "
191- " not set. Upgrade the caller to W3C Trace Context Level 2." );
160+ static std::atomic<bool > warned{false };
161+ if (!warned.exchange (true ))
162+ {
163+ OTEL_INTERNAL_LOG_WARN (
164+ " ProbabilitySampler presumes TraceID randomness, but the W3C random trace flag is "
165+ " not set. Upgrade the caller to W3C Trace Context Level 2." );
166+ }
192167 }
168+ randomness = GetRandomnessFromTraceId (trace_id);
193169 }
194- randomness = RandomnessFromTraceId (trace_id) ;
170+ drop = randomness < threshold_ ;
195171 }
196172
197- if (randomness < threshold_)
198- return {Decision::DROP , nullptr , {}};
173+ if (drop)
174+ {
175+ OtelTraceState ot_state = OtelTraceState::Parse (ot_value);
176+ ot_state.has_threshold = false ;
177+ std::string dropped_ot = ot_state.Serialize ();
178+ auto trace_state = parent_trace_state->Delete (kOtTraceStateKey );
179+ if (!dropped_ot.empty ())
180+ trace_state = trace_state->Set (kOtTraceStateKey , dropped_ot);
181+ return {Decision::DROP , nullptr , trace_state};
182+ }
199183
200184 std::string new_ot_value = SetThresholdSubKey (ot_value, EncodeThreshold (threshold_));
201185 if (!trace_api::TraceState::IsValidValue (new_ot_value))
0 commit comments