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
78 changes: 22 additions & 56 deletions sentry_sdk/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,14 +525,12 @@ def get_dynamic_sampling_context(self):
"""
Returns the Dynamic Sampling Context from the Propagation Context.
If not existing, creates a new one.

Deprecated: Logic moved to PropagationContext, don't use directly.
"""
if self._propagation_context is None:
return None

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

return self._propagation_context.dynamic_sampling_context

def get_traceparent(self, *args, **kwargs):
Expand All @@ -547,16 +545,13 @@ def get_traceparent(self, *args, **kwargs):
if has_tracing_enabled(client.options) and self.span is not None:
return self.span.to_traceparent()

# If this scope has a propagation context, return traceparent from there
if self._propagation_context is not None:
traceparent = "%s-%s" % (
self._propagation_context.trace_id,
self._propagation_context.span_id,
)
return traceparent
# else return traceparent from the propagation context
propagation_context = self.get_active_propagation_context()
if propagation_context is not None:
return propagation_context.to_traceparent()

# Fall back to isolation scope's traceparent. It always has one
return self.get_isolation_scope().get_traceparent()
# TODO-neel will never happen
Copy link
Member Author

@sl0thentr0py sl0thentr0py Dec 10, 2025

Choose a reason for hiding this comment

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

follow up PR
#5217

return None

def get_baggage(self, *args, **kwargs):
# type: (Any, Any) -> Optional[Baggage]
Expand All @@ -570,12 +565,13 @@ def get_baggage(self, *args, **kwargs):
if has_tracing_enabled(client.options) and self.span is not None:
return self.span.to_baggage()

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

# Fall back to isolation scope's baggage. It always has one
return self.get_isolation_scope().get_baggage()
# TODO-neel will never happen
return None

def get_trace_context(self):
# type: () -> Dict[str, Any]
Expand All @@ -599,7 +595,7 @@ def get_trace_context(self):
"trace_id": propagation_context.trace_id,
"span_id": propagation_context.span_id,
"parent_span_id": propagation_context.parent_span_id,
"dynamic_sampling_context": self.get_dynamic_sampling_context(),
"dynamic_sampling_context": propagation_context.dynamic_sampling_context,
}

def trace_propagation_meta(self, *args, **kwargs):
Expand All @@ -616,36 +612,19 @@ def trace_propagation_meta(self, *args, **kwargs):

meta = ""

sentry_trace = self.get_traceparent()
if sentry_trace is not None:
meta += '<meta name="%s" content="%s">' % (
SENTRY_TRACE_HEADER_NAME,
sentry_trace,
)

baggage = self.get_baggage()
if baggage is not None:
meta += '<meta name="%s" content="%s">' % (
BAGGAGE_HEADER_NAME,
baggage.serialize(),
)
for name, content in self.iter_trace_propagation_headers():
meta += f'<meta name="{name}" content="{content}">'

return meta

def iter_headers(self):
# type: () -> Iterator[Tuple[str, str]]
"""
Creates a generator which returns the `sentry-trace` and `baggage` headers from the Propagation Context.
Deprecated: use PropagationContext.iter_headers instead.
"""
if self._propagation_context is not None:
traceparent = self.get_traceparent()
if traceparent is not None:
yield SENTRY_TRACE_HEADER_NAME, traceparent

dsc = self.get_dynamic_sampling_context()
if dsc is not None:
baggage = Baggage(dsc).serialize()
yield BAGGAGE_HEADER_NAME, baggage
yield from self._propagation_context.iter_headers()

def iter_trace_propagation_headers(self, *args, **kwargs):
# type: (Any, Any) -> Generator[Tuple[str, str], None, None]
Expand All @@ -671,23 +650,10 @@ def iter_trace_propagation_headers(self, *args, **kwargs):
for header in span.iter_headers():
yield header
else:
# If this scope has a propagation context, return headers from there
# (it could be that self is not the current scope nor the isolation scope)
if self._propagation_context is not None:
for header in self.iter_headers():
propagation_context = self.get_active_propagation_context()
if propagation_context is not None:
for header in propagation_context.iter_headers():
yield header
else:
# otherwise try headers from current scope
current_scope = self.get_current_scope()
if current_scope._propagation_context is not None:
for header in current_scope.iter_headers():
yield header
else:
# otherwise fall back to headers from isolation scope
isolation_scope = self.get_isolation_scope()
if isolation_scope._propagation_context is not None:
for header in isolation_scope.iter_headers():
yield header

def get_active_propagation_context(self):
# type: () -> Optional[PropagationContext]
Expand Down
41 changes: 36 additions & 5 deletions sentry_sdk/tracing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
from typing import Generator
from typing import Optional
from typing import Union
from typing import Iterator
from typing import Tuple

from types import FrameType

Expand Down Expand Up @@ -506,7 +508,28 @@ def span_id(self, value):
@property
def dynamic_sampling_context(self):
# type: () -> Optional[Dict[str, Any]]
return self.baggage.dynamic_sampling_context() if self.baggage else None
return self.get_baggage().dynamic_sampling_context()

def to_traceparent(self):
# type: () -> str
return f"{self.trace_id}-{self.span_id}"

def get_baggage(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Same nit as above

Suggested change
def get_baggage(self):
def to_baggage(self):

Copy link
Member Author

@sl0thentr0py sl0thentr0py Dec 11, 2025

Choose a reason for hiding this comment

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

we actually don't use Span.to_baggage anywhere and the Span.iter_headers uses get_baggage from the transaction itself so I'll leave this as get_baggage.

# type: () -> Baggage
if self.baggage is None:
self.baggage = Baggage.populate_from_propagation_context(self)
return self.baggage

def iter_headers(self):
# type: () -> Iterator[Tuple[str, str]]
"""
Creates a generator which returns the propagation_context's ``sentry-trace`` and ``baggage`` headers.
"""
yield SENTRY_TRACE_HEADER_NAME, self.to_traceparent()

baggage = self.get_baggage().serialize()
if baggage:
yield BAGGAGE_HEADER_NAME, baggage

def update(self, other_dict):
# type: (Dict[str, Any]) -> None
Expand Down Expand Up @@ -649,21 +672,29 @@ def from_incoming_header(
@classmethod
def from_options(cls, scope):
# type: (sentry_sdk.scope.Scope) -> Optional[Baggage]
"""
Deprecated: use populate_from_propagation_context
"""
if scope._propagation_context is None:
return Baggage({})

return Baggage.populate_from_propagation_context(scope._propagation_context)

@classmethod
def populate_from_propagation_context(cls, propagation_context):
# type: (PropagationContext) -> Baggage
sentry_items = {} # type: Dict[str, str]
third_party_items = ""
mutable = False

client = sentry_sdk.get_client()

if not client.is_active() or scope._propagation_context is None:
if not client.is_active():
return Baggage(sentry_items)

options = client.options
propagation_context = scope._propagation_context

if propagation_context is not None:
sentry_items["trace_id"] = propagation_context.trace_id
sentry_items["trace_id"] = propagation_context.trace_id

if options.get("environment"):
sentry_items["environment"] = options["environment"]
Expand Down
6 changes: 3 additions & 3 deletions tests/test_propagationcontext.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_empty_context():

assert ctx.parent_span_id is None
assert ctx.parent_sampled is None
assert ctx.dynamic_sampling_context is None
assert ctx.dynamic_sampling_context == {}


def test_context_with_values():
Expand Down Expand Up @@ -72,7 +72,7 @@ def test_property_setters():
assert ctx.trace_id == "X234567890abcdef1234567890abcdef"
assert ctx._span_id == "X234567890abcdef"
assert ctx.span_id == "X234567890abcdef"
assert ctx.dynamic_sampling_context is None
assert ctx.dynamic_sampling_context == {}


def test_update():
Expand All @@ -93,7 +93,7 @@ def test_update():
assert ctx._span_id is not None
assert ctx.parent_span_id == "Z234567890abcdef"
assert not ctx.parent_sampled
assert ctx.dynamic_sampling_context is None
assert ctx.dynamic_sampling_context == {}

assert not hasattr(ctx, "foo")

Expand Down