Skip to content

Implement trace_propagation_targets for propagator #4460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 16, 2025
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
35 changes: 23 additions & 12 deletions sentry_sdk/opentelemetry/propagator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
SpanContext,
TraceFlags,
)
from opentelemetry.semconv.trace import SpanAttributes

import sentry_sdk
from sentry_sdk.consts import (
BAGGAGE_HEADER_NAME,
SENTRY_TRACE_HEADER_NAME,
Expand All @@ -30,7 +32,11 @@
SENTRY_TRACE_KEY,
SENTRY_SCOPES_KEY,
)
from sentry_sdk.tracing_utils import Baggage, extract_sentrytrace_data
from sentry_sdk.tracing_utils import (
Baggage,
extract_sentrytrace_data,
should_propagate_trace,
)

from typing import TYPE_CHECKING

Expand Down Expand Up @@ -89,18 +95,23 @@ def extract(self, carrier, context=None, getter=default_getter):

def inject(self, carrier, context=None, setter=default_setter):
# type: (CarrierT, Optional[Context], Setter[CarrierT]) -> None
if context is None:
context = get_current()

scopes = get_value(SENTRY_SCOPES_KEY, context)
if scopes:
scopes = cast("tuple[scope.PotelScope, scope.PotelScope]", scopes)
(current_scope, _) = scopes

# TODO-neel-potel check trace_propagation_targets
# TODO-neel-potel test propagator works with twp
for key, value in current_scope.iter_trace_propagation_headers():
setter.set(carrier, key, value)
if not scopes:
return

scopes = cast("tuple[scope.PotelScope, scope.PotelScope]", scopes)
(current_scope, _) = scopes

span = current_scope.span
if span:
span_url = span.get_attribute(SpanAttributes.HTTP_URL)
if span_url and not should_propagate_trace(
sentry_sdk.get_client(), span_url
):
return

for key, value in current_scope.iter_trace_propagation_headers():
setter.set(carrier, key, value)

@property
def fields(self):
Expand Down
66 changes: 66 additions & 0 deletions tests/opentelemetry/test_propagator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from opentelemetry.trace.propagation import get_current_span
from opentelemetry.propagators.textmap import DefaultSetter
from opentelemetry.semconv.trace import SpanAttributes

import sentry_sdk
from sentry_sdk.consts import MATCH_ALL
from sentry_sdk.opentelemetry.consts import (
SENTRY_BAGGAGE_KEY,
SENTRY_TRACE_KEY,
Expand Down Expand Up @@ -208,3 +210,67 @@ def test_inject_head_sdk(sentry_init):
assert carrier["baggage"] == SortedBaggage(
expected_baggage.format(trace_id=span.trace_id)
)


@pytest.mark.parametrize(
"trace_propagation_targets,url,trace_propagated",
[
# No targets - should not propagate
([], "https://example.com/api/users", False),
(None, "https://example.com/api/users", False),
# MATCH_ALL - should propagate
([MATCH_ALL], "https://example.com/api/users", True),
# Exact match - should propagate
(["https://example.com"], "https://example.com/api/users", True),
(["https://example.com/"], "https://example.com/api/users", True),
# No match - should not propagate
(["https://example.com"], "https://other-domain.com/api/users", False),
(["https://example.com/"], "https://other-domain.com/api/users", False),
# Regex patterns
(
["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"],
"https://good.example.net/api",
True,
),
(
["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"],
"https://example.net/api",
False,
),
# HTTP vs HTTPS
(["https://example.com"], "http://example.com/api/users", False),
(["http://example.com"], "https://example.com/api/users", False),
# Path matching
(["https://example.com/api"], "https://example.com/api/users", True),
(["https://example.com/api"], "https://example.com/other/path", False),
],
)
def test_propagator_trace_propagation_targets(
sentry_init,
trace_propagation_targets,
url,
trace_propagated,
):
"""Test that the propagator respects trace_propagation_targets for HTTP spans."""
sentry_init(
trace_propagation_targets=trace_propagation_targets,
traces_sample_rate=1.0,
)

carrier = {}
setter = DefaultSetter()

# Create a real HTTP span with the test URL
with sentry_sdk.start_span(name="http.client") as span:
span.set_attribute(SpanAttributes.HTTP_METHOD, "GET")
span.set_attribute(SpanAttributes.HTTP_URL, url)

# Test the propagator
SentryPropagator().inject(carrier, setter=setter)

if trace_propagated:
assert "sentry-trace" in carrier
assert "baggage" in carrier
else:
assert "sentry-trace" not in carrier
assert "baggage" not in carrier
Loading