diff --git a/sentry_sdk/opentelemetry/propagator.py b/sentry_sdk/opentelemetry/propagator.py index 6062e5643a..16a0d19cc9 100644 --- a/sentry_sdk/opentelemetry/propagator.py +++ b/sentry_sdk/opentelemetry/propagator.py @@ -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, @@ -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 @@ -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): diff --git a/tests/opentelemetry/test_propagator.py b/tests/opentelemetry/test_propagator.py index 49437fa896..2f802daafb 100644 --- a/tests/opentelemetry/test_propagator.py +++ b/tests/opentelemetry/test_propagator.py @@ -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, @@ -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