@@ -281,6 +281,10 @@ def continue_from_headers(
281281
282282 if sentrytrace_kwargs is not None :
283283 kwargs .update (sentrytrace_kwargs )
284+
285+ # If there's an incoming sentry-trace but no incoming baggage header,
286+ # for instance in traces coming from older SDKs,
287+ # baggage will be empty and immutable and won't be populated as head SDK.
284288 baggage .freeze ()
285289
286290 kwargs .update (extract_tracestate_data (headers .get ("tracestate" )))
@@ -309,8 +313,8 @@ def iter_headers(self):
309313 if tracestate :
310314 yield "tracestate" , tracestate
311315
312- if self .containing_transaction and self . containing_transaction . _baggage :
313- baggage = self .containing_transaction ._baggage .serialize ()
316+ if self .containing_transaction :
317+ baggage = self .containing_transaction .get_baggage () .serialize ()
314318 if baggage :
315319 yield "baggage" , baggage
316320
@@ -513,11 +517,10 @@ def get_trace_context(self):
513517 if sentry_tracestate :
514518 rv ["tracestate" ] = sentry_tracestate
515519
516- # TODO-neel populate fresh if head SDK
517- if self .containing_transaction and self .containing_transaction ._baggage :
520+ if self .containing_transaction :
518521 rv [
519522 "dynamic_sampling_context"
520- ] = self .containing_transaction ._baggage .dynamic_sampling_context ()
523+ ] = self .containing_transaction .get_baggage () .dynamic_sampling_context ()
521524
522525 return rv
523526
@@ -527,6 +530,7 @@ class Transaction(Span):
527530 "name" ,
528531 "source" ,
529532 "parent_sampled" ,
533+ "sample_rate" ,
530534 # the sentry portion of the `tracestate` header used to transmit
531535 # correlation context for server-side dynamic sampling, of the form
532536 # `sentry=xxxxx`, where `xxxxx` is the base64-encoded json of the
@@ -562,6 +566,7 @@ def __init__(
562566 Span .__init__ (self , ** kwargs )
563567 self .name = name
564568 self .source = source
569+ self .sample_rate = None # type: Optional[float]
565570 self .parent_sampled = parent_sampled
566571 # if tracestate isn't inherited and set here, it will get set lazily,
567572 # either the first time an outgoing request needs it for a header or the
@@ -570,7 +575,7 @@ def __init__(
570575 self ._third_party_tracestate = third_party_tracestate
571576 self ._measurements = {} # type: Dict[str, Any]
572577 self ._profile = None # type: Optional[Sampler]
573- self ._baggage = baggage
578+ self ._baggage = baggage # type: Optional[Baggage]
574579
575580 def __repr__ (self ):
576581 # type: () -> str
@@ -708,6 +713,17 @@ def to_json(self):
708713
709714 return rv
710715
716+ def get_baggage (self ):
717+ # type: () -> Baggage
718+ """
719+ The first time a new baggage with sentry items is made,
720+ it will be frozen.
721+ """
722+ if not self ._baggage or self ._baggage .mutable :
723+ self ._baggage = Baggage .populate_from_transaction (self )
724+
725+ return self ._baggage
726+
711727 def _set_initial_sampling_decision (self , sampling_context ):
712728 # type: (SamplingContext) -> None
713729 """
@@ -773,6 +789,9 @@ def _set_initial_sampling_decision(self, sampling_context):
773789 self .sampled = False
774790 return
775791
792+ # used to create baggage value for head SDKs in dynamic sampling
793+ self .sample_rate = float (sample_rate )
794+
776795 # if the function returned 0 (or false), or if `traces_sample_rate` is
777796 # 0, it's a sign the transaction should be dropped
778797 if not sample_rate :
0 commit comments