1+ from typing import cast
12from random import random
23
34from opentelemetry import trace
67from opentelemetry .trace .span import TraceState
78
89import sentry_sdk
9- from sentry_sdk .integrations .opentelemetry .consts import SENTRY_TRACE_STATE_DROPPED
1010from sentry_sdk .tracing_utils import has_tracing_enabled
1111from sentry_sdk .utils import is_valid_sample_rate , logger
12+ from sentry_sdk .integrations .opentelemetry .consts import (
13+ TRACESTATE_SAMPLED_KEY ,
14+ TRACESTATE_SAMPLE_RATE_KEY ,
15+ )
1216
13- from typing import TYPE_CHECKING , Optional , Sequence
17+ from typing import TYPE_CHECKING
1418
1519if TYPE_CHECKING :
20+ from typing import Optional , Sequence , Union
1621 from opentelemetry .context import Context
1722 from opentelemetry .trace import Link , SpanKind
1823 from opentelemetry .trace .span import SpanContext
@@ -32,30 +37,42 @@ def get_parent_sampled(parent_context, trace_id):
3237 if parent_context .trace_flags .sampled :
3338 return True
3439
35- dropped = parent_context .trace_state .get (SENTRY_TRACE_STATE_DROPPED ) == "true"
36- if dropped :
40+ dsc_sampled = parent_context .trace_state .get (TRACESTATE_SAMPLED_KEY )
41+ if dsc_sampled == "true" :
42+ return True
43+ elif dsc_sampled == "false" :
3744 return False
3845
39- # TODO-anton: fall back to sampling decision in DSC (for this die DSC needs to be set in the trace_state)
40-
4146 return None
4247
4348
44- def dropped_result (span_context ):
45- # type: (SpanContext) -> SamplingResult
46- trace_state = span_context .trace_state .update (SENTRY_TRACE_STATE_DROPPED , "true" )
49+ def dropped_result (span_context , attributes , sample_rate = None ):
50+ # type: (SpanContext, Attributes, Optional[float]) -> SamplingResult
51+ # note that trace_state.add will NOT overwrite existing entries
52+ # so these will only be added the first time in a root span sampling decision
53+ trace_state = span_context .trace_state .add (TRACESTATE_SAMPLED_KEY , "false" )
54+ if sample_rate :
55+ trace_state = trace_state .add (TRACESTATE_SAMPLE_RATE_KEY , str (sample_rate ))
4756
4857 return SamplingResult (
4958 Decision .DROP ,
59+ attributes = attributes ,
5060 trace_state = trace_state ,
5161 )
5262
5363
54- def sampled_result (span_context ):
55- # type: (SpanContext) -> SamplingResult
64+ def sampled_result (span_context , attributes , sample_rate ):
65+ # type: (SpanContext, Attributes, float) -> SamplingResult
66+ # note that trace_state.add will NOT overwrite existing entries
67+ # so these will only be added the first time in a root span sampling decision
68+ trace_state = span_context .trace_state .add (TRACESTATE_SAMPLED_KEY , "true" ).add (
69+ TRACESTATE_SAMPLE_RATE_KEY , str (sample_rate )
70+ )
71+
5672 return SamplingResult (
5773 Decision .RECORD_AND_SAMPLE ,
58- trace_state = span_context .trace_state ,
74+ attributes = attributes ,
75+ trace_state = trace_state ,
5976 )
6077
6178
@@ -77,7 +94,7 @@ def should_sample(
7794
7895 # No tracing enabled, thus no sampling
7996 if not has_tracing_enabled (client .options ):
80- return dropped_result (parent_span_context )
97+ return dropped_result (parent_span_context , attributes )
8198
8299 sample_rate = None
83100
@@ -112,16 +129,16 @@ def should_sample(
112129 logger .warning (
113130 f"[Tracing] Discarding { name } because of invalid sample rate."
114131 )
115- return dropped_result (parent_span_context )
132+ return dropped_result (parent_span_context , attributes )
116133
117134 # Roll the dice on sample rate
118- sampled = random () < float (sample_rate )
135+ sample_rate = float (cast ("Union[bool, float, int]" , sample_rate ))
136+ sampled = random () < sample_rate
119137
120- # TODO-neel-potel set sample rate as attribute for DSC
121138 if sampled :
122- return sampled_result (parent_span_context )
139+ return sampled_result (parent_span_context , attributes , sample_rate )
123140 else :
124- return dropped_result (parent_span_context )
141+ return dropped_result (parent_span_context , attributes , sample_rate )
125142
126143 def get_description (self ) -> str :
127144 return self .__class__ .__name__
0 commit comments