Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions sentry_sdk/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,7 @@ def get_dynamic_sampling_context(self):

baggage = self.get_baggage()
if baggage is not None:
self._propagation_context.dynamic_sampling_context = (
baggage.dynamic_sampling_context()
)
self._propagation_context.baggage = baggage

return self._propagation_context.dynamic_sampling_context

Expand Down Expand Up @@ -573,13 +571,7 @@ def get_baggage(self, *args, **kwargs):

# If this scope has a propagation context, return baggage from there
if self._propagation_context is not None:
dynamic_sampling_context = (
self._propagation_context.dynamic_sampling_context
)
if dynamic_sampling_context is None:
return Baggage.from_options(self)
else:
return Baggage(dynamic_sampling_context)
return self._propagation_context.baggage or Baggage.from_options(self)

# Fall back to isolation scope's baggage. It always has one
return self.get_isolation_scope().get_baggage()
Expand Down Expand Up @@ -1099,9 +1091,9 @@ def start_transaction(
if transaction.sample_rate is not None:
propagation_context = self.get_active_propagation_context()
if propagation_context:
dsc = propagation_context.dynamic_sampling_context
if dsc is not None:
dsc["sample_rate"] = str(transaction.sample_rate)
baggage = propagation_context.baggage
if baggage is not None:
baggage.sentry_items["sample_rate"] = str(transaction.sample_rate)
if transaction._baggage:
transaction._baggage.sentry_items["sample_rate"] = str(
transaction.sample_rate
Expand Down
48 changes: 26 additions & 22 deletions sentry_sdk/tracing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ class PropagationContext:
"_span_id",
"parent_span_id",
"parent_sampled",
"dynamic_sampling_context",
"baggage",
)

def __init__(
Expand All @@ -421,6 +421,7 @@ def __init__(
parent_span_id=None, # type: Optional[str]
parent_sampled=None, # type: Optional[bool]
dynamic_sampling_context=None, # type: Optional[Dict[str, str]]
Copy link
Member Author

@sl0thentr0py sl0thentr0py Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not removing the constructor parameter because that would be technically breaking but it does nothing now.
@sentrivana if we consider this class purely internal, I can also remove, wdyt?
Also, we never call this constructor with any arguments ourselves.

EDIT: Ignore, added backwards compat.

baggage=None, # type: Optional[Baggage]
):
# type: (...) -> None
self._trace_id = trace_id
Expand All @@ -438,8 +439,12 @@ def __init__(
Important when the parent span originated in an upstream service,
because we want to sample the whole trace, or nothing from the trace."""

self.dynamic_sampling_context = dynamic_sampling_context
"""Data that is used for dynamic sampling decisions."""
self.baggage = baggage
"""Parsed baggage header that is used for dynamic sampling decisions."""

"""DEPRECATED this only exists for backwards compat of constructor."""
if baggage is None and dynamic_sampling_context is not None:
self.baggage = Baggage(dynamic_sampling_context)

@classmethod
def from_incoming_data(cls, incoming_data):
Expand All @@ -456,9 +461,7 @@ def from_incoming_data(cls, incoming_data):

baggage_header = normalized_data.get(BAGGAGE_HEADER_NAME)
if baggage_header:
propagation_context.dynamic_sampling_context = Baggage.from_incoming_header(
baggage_header
).dynamic_sampling_context()
propagation_context.baggage = Baggage.from_incoming_header(baggage_header)

propagation_context._fill_sample_rand()

Expand Down Expand Up @@ -493,6 +496,11 @@ def span_id(self, value):
# type: (str) -> None
self._span_id = value

@property
def dynamic_sampling_context(self):
# type: () -> Optional[Dict[str, Any]]
return self.baggage.dynamic_sampling_context() if self.baggage else None

def update(self, other_dict):
# type: (Dict[str, Any]) -> None
"""
Expand All @@ -506,20 +514,20 @@ def update(self, other_dict):

def __repr__(self):
# type: (...) -> str
return "<PropagationContext _trace_id={} _span_id={} parent_span_id={} parent_sampled={} dynamic_sampling_context={}>".format(
return "<PropagationContext _trace_id={} _span_id={} parent_span_id={} parent_sampled={} baggage={}>".format(
self._trace_id,
self._span_id,
self.parent_span_id,
self.parent_sampled,
self.dynamic_sampling_context,
self.baggage,
)

def _fill_sample_rand(self):
# type: () -> None
"""
Ensure that there is a valid sample_rand value in the dynamic_sampling_context.
Ensure that there is a valid sample_rand value in the baggage.

If there is a valid sample_rand value in the dynamic_sampling_context, we keep it.
If there is a valid sample_rand value in the baggage, we keep it.
Otherwise, we generate a sample_rand value according to the following:

- If we have a parent_sampled value and a sample_rate in the DSC, we compute
Expand All @@ -532,23 +540,19 @@ def _fill_sample_rand(self):

The sample_rand is deterministically generated from the trace_id, if present.

This function does nothing if there is no dynamic_sampling_context.
This function does nothing if there is no baggage.
"""
if self.dynamic_sampling_context is None:
if self.baggage is None:
return

sample_rand = try_convert(
float, self.dynamic_sampling_context.get("sample_rand")
)
sample_rand = try_convert(float, self.baggage.sentry_items.get("sample_rand"))
if sample_rand is not None and 0 <= sample_rand < 1:
# sample_rand is present and valid, so don't overwrite it
return

# Get the sample rate and compute the transformation that will map the random value
# to the desired range: [0, 1), [0, sample_rate), or [sample_rate, 1).
sample_rate = try_convert(
float, self.dynamic_sampling_context.get("sample_rate")
)
sample_rate = try_convert(float, self.baggage.sentry_items.get("sample_rate"))
lower, upper = _sample_rand_range(self.parent_sampled, sample_rate)

try:
Expand All @@ -564,15 +568,15 @@ def _fill_sample_rand(self):
)
return

self.dynamic_sampling_context["sample_rand"] = f"{sample_rand:.6f}" # noqa: E231
self.baggage.sentry_items["sample_rand"] = f"{sample_rand:.6f}" # noqa: E231

def _sample_rand(self):
# type: () -> Optional[str]
"""Convenience method to get the sample_rand value from the dynamic_sampling_context."""
if self.dynamic_sampling_context is None:
"""Convenience method to get the sample_rand value from the baggage."""
if self.baggage is None:
return None

return self.dynamic_sampling_context.get("sample_rand")
return self.baggage.sentry_items.get("sample_rand")


class Baggage:
Expand Down