From 99a3c7f3620b8f8fddc158689316b6847b6d01bb Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 10:49:34 +0200 Subject: [PATCH 01/14] fix(sampling): sentry-trace takes precedence over baggage --- sentry_sdk/tracing_utils.py | 28 ++++-------- tests/tracing/test_span_streaming.py | 66 +++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index b1a9bec516..d75d94efd6 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -1575,20 +1575,6 @@ def add_sentry_baggage_to_headers( ) -def _get_effective_sample_rate( - client: "Any", propagation_context: "PropagationContext" -) -> "Union[float, bool]": - if propagation_context.parent_sampled is not None: - propagation_context_sample_rate = propagation_context._sample_rate() - - if propagation_context_sample_rate is not None: - return propagation_context_sample_rate - else: - return propagation_context.parent_sampled - else: - return client.options["traces_sample_rate"] - - def _make_sampling_decision( name: str, attributes: "Optional[Attributes]", @@ -1651,13 +1637,15 @@ def _make_sampling_decision( "[Tracing] traces_sampler raised; falling back to parent sample rate or traces_sample_rate", exc_info=True, ) - sample_rate = _get_effective_sample_rate( - client=client, propagation_context=propagation_context - ) + if propagation_context.parent_sampled is not None: + sample_rate = propagation_context.parent_sampled + else: + sample_rate = client.options["traces_sample_rate"] else: - sample_rate = _get_effective_sample_rate( - client=client, propagation_context=propagation_context - ) + if propagation_context.parent_sampled is not None: + sample_rate = propagation_context.parent_sampled + else: + sample_rate = client.options["traces_sample_rate"] # Validate whether the sample_rate we got is actually valid. Since # traces_sampler is user-provided, it could return anything. diff --git a/tests/tracing/test_span_streaming.py b/tests/tracing/test_span_streaming.py index 669d15deaf..6b155e4a45 100644 --- a/tests/tracing/test_span_streaming.py +++ b/tests/tracing/test_span_streaming.py @@ -988,10 +988,72 @@ def test_outgoing_traceparent_and_baggage_incoming_trace( traceparent == f"{trace_id}-{span_id}-{'1' if parent_sampled else '0'}" ) - # As we've received incoming baggage, we mustn't modify it ourselves and - # have to propagate it as-is baggage = sentry_sdk.get_baggage() baggage_items = dict(tuple(item.split("=")) for item in baggage.split(",")) + + # As we've received incoming baggage, we shouldn't modify it ourselves + # and should propagate it as-is. However, in the case where our + # effective sample rate overrides the parent sample rate, we update the + # sample rate in the baggage as a consequence of updating the sample rate + # in the DSC. + if traces_sample_rate is not None: + incoming_baggage["sentry-sample_rate"] = str(float(parent_sampled)) + + assert baggage_items == incoming_baggage + + +def test_outgoing_traceparent_and_baggage_inconsistent_incoming_trace( + sentry_init, +): + # We correctly propagate even if we get a sample_rate/sample_rand/sampled + # baggage combination from upstream that doesn't align with the parent + # sampling decision + sentry_init( + traces_sample_rate=1.0, + trace_lifecycle="stream", + ) + + trace_id = "0af7651916cd43dd8448eb211c80319c" + parent_span_id = "b7ad6b7169203331" + + incoming_baggage = { + "sentry-trace_id": trace_id, + } + + # Baggage says sampled, sentry-trace says unsampled. sentry-trace takes + # precedence + incoming_sentry_trace = f"{trace_id}-{parent_span_id}-0" + incoming_baggage.update( + { + "sentry-sample_rate": "0.75", + "sentry-sample_rand": "0.500000", + "sentry-sampled": "true", + } + ) + + sentry_sdk.traces.continue_trace( + { + "sentry-trace": incoming_sentry_trace, + "baggage": ",".join( + sorted([f"{k}={v}" for k, v in incoming_baggage.items()]) + ), + } + ) + + with sentry_sdk.traces.start_span(name="span") as span: + assert span.sampled is False + + traceparent = sentry_sdk.get_traceparent() + + span_id = span.span_id + assert traceparent == f"{trace_id}-{span_id}-0" + + # We shouldn't be updating incoming baggage, but in the case where our + # effective sample rate overrides the parent sample rate, we do this as + # a consequence of updating the sample rate in the DSC. + baggage = sentry_sdk.get_baggage() + baggage_items = dict(tuple(item.split("=")) for item in baggage.split(",")) + incoming_baggage["sentry-sample_rate"] = "0.0" assert baggage_items == incoming_baggage From de26c1a5950b892c11269a335f6396fa0dade680 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 11:08:43 +0200 Subject: [PATCH 02/14] . --- tests/integrations/stdlib/test_httplib.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/integrations/stdlib/test_httplib.py b/tests/integrations/stdlib/test_httplib.py index dff91087f4..2282045e78 100644 --- a/tests/integrations/stdlib/test_httplib.py +++ b/tests/integrations/stdlib/test_httplib.py @@ -318,7 +318,7 @@ def getresponse(self, *args, **kwargs): expected_outgoing_baggage = ( "sentry-trace_id=771a43a4192642f0b136d5159a501700," "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337," + "sentry-sample_rate=1.0," "sentry-user_id=Am%C3%A9lie," "sentry-sample_rand=0.000005," "sentry-sampled=true" @@ -345,8 +345,6 @@ def getresponse(self, *args, **kwargs): sampled=1, ) - # Note: the sample rate here is actually wrong. It's fixed in the - # streaming path expected_outgoing_baggage = ( "sentry-trace_id=771a43a4192642f0b136d5159a501700," "sentry-public_key=49d0f7386ad645858ae85020e393bef3," From 5047feb2ad92b233cbd31b5950a9e496db970a95 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 9 Jul 2026 14:20:45 +0200 Subject: [PATCH 03/14] test: Add streaming integration tests --- sentry_sdk/traces.py | 1 + tests/tracing/test_integration_tests.py | 445 +++++++++++++++++++++++- 2 files changed, 445 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index cbf650a265..0131f694f1 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -581,6 +581,7 @@ def _set_segment_attributes(self) -> None: self.set_attribute( SPANDATA.SENTRY_SDK_INTEGRATIONS, sorted(client.integrations.keys()) ) + self.set_attribute("sentry.span.source", SegmentSource.CUSTOM.value) if client.options.get("dist") and SPANDATA.SENTRY_DIST not in self._attributes: self.set_attribute( diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 1408f3cffc..d4b0b38206 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -56,6 +56,43 @@ def test_basic(sentry_init, capture_events, sample_rate): assert not events +@pytest.mark.parametrize("sample_rate", [0.0, 1.0]) +def test_basic_span_streaming(sentry_init, capture_items, sample_rate): + sentry_init( + traces_sample_rate=sample_rate, _experiments={"trace_lifecycle": "stream"} + ) + items = capture_items() + + with sentry_sdk.traces.start_span(name="hi"): + with pytest.raises(ZeroDivisionError): + with sentry_sdk.traces.start_span(name="foo"): + 1 / 0 + + with sentry_sdk.traces.start_span(name="bar"): + pass + + sentry_sdk.flush() + + if sample_rate: + assert len(items) == 3 + span1, span2, parent_span = [item.payload for item in items] + + assert parent_span["name"] == "hi" + assert parent_span["attributes"]["sentry.span.source"] == "custom" + + assert span1["status"] == "error" + assert span1["name"] == "foo" + assert span1["attributes"]["sentry.segment.id"] == parent_span["span_id"] + assert span1["attributes"]["sentry.segment.name"] == "hi" + + assert span2["status"] == "ok" + assert span2["name"] == "bar" + assert span1["attributes"]["sentry.segment.id"] == parent_span["span_id"] + assert span1["attributes"]["sentry.segment.name"] == "hi" + else: + assert not items + + @pytest.mark.parametrize("parent_sampled", [True, False, None]) @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) def test_continue_trace(sentry_init, capture_envelopes, parent_sampled, sample_rate): @@ -151,6 +188,96 @@ def test_continue_trace(sentry_init, capture_envelopes, parent_sampled, sample_r assert message_payload["message"] == "hello" +@pytest.mark.parametrize("parent_sampled", [True, False, None]) +@pytest.mark.parametrize("sample_rate", [0.0, 1.0]) +def test_continue_trace_span_streaming( + sentry_init, capture_envelopes, parent_sampled, sample_rate +): + """ + Ensure data is actually passed along via headers, and that they are read + correctly. + """ + sentry_init( + traces_sample_rate=sample_rate, _experiments={"trace_lifecycle": "stream"} + ) + envelopes = capture_envelopes() + + # make a parent segment (normally this would be in a different service) + with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.traces.start_span(name="hey") as old_span: + headers = dict( + sentry_sdk.get_current_scope().iter_trace_propagation_headers(old_span) + ) + headers["baggage"] = ( + "other-vendor-value-1=foo;bar;baz," + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337," + "sentry-user_id=Amelie," + "sentry-sample_rand=0.250000," + "other-vendor-value-2=foo;bar;" + ) + + # child segment, to prove that we can read 'sentry-trace' header data correctly + sentry_sdk.traces.continue_trace(headers) + child_segment = sentry_sdk.traces.start_span(name="WRONG") + assert child_segment is not None + assert child_segment._parent_sampled == parent_sampled + assert child_segment.trace_id == old_span.trace_id + assert child_segment._parent_span_id == old_span.span_id + assert child_segment.span_id != old_span.span_id + + baggage = child_segment._baggage + assert baggage + assert not baggage.mutable + assert baggage.sentry_items == { + "public_key": "49d0f7386ad645858ae85020e393bef3", + "trace_id": "771a43a4192642f0b136d5159a501700", + "user_id": "Amelie", + "sample_rand": "0.250000", + "sample_rate": "0.01337", + } + + # change the transaction name from "WRONG" to make sure the change + # is reflected in the final data + sentry_sdk.get_current_scope().transaction = "ho" + capture_message("hello") + + if parent_sampled is False or (sample_rate == 0 and parent_sampled is None): + # in this case the child transaction won't be captured + trace1, message = envelopes + message_payload = message.get_event() + trace1_payload = trace1.items[0].payload.json + + assert trace1_payload["transaction"] == "hi" + else: + trace1, message, trace2 = envelopes + trace1_payload = trace1.items[0].payload.json + message_payload = message.get_event() + trace2_payload = trace2.items[0].payload.json + + assert trace1_payload["attributes"]["sentry.segment.name"] == "hi" + assert trace2_payload["attributes"]["sentry.segment.name"] == "ho" + + assert ( + trace1_payload["trace_id"] + == trace2_payload["trace_id"] + == child_segment.trace_id + == message_payload["contexts"]["trace"]["trace_id"] + ) + + assert trace2.headers["trace"] == baggage.dynamic_sampling_context() + assert trace2.headers["trace"] == { + "public_key": "49d0f7386ad645858ae85020e393bef3", + "trace_id": "771a43a4192642f0b136d5159a501700", + "user_id": "Amelie", + "sample_rand": "0.250000", + "sample_rate": str(sample_rate), + } + + assert message_payload["message"] == "hello" + + @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) def test_propagate_traces_deprecation_warning(sentry_init, sample_rate): sentry_init(traces_sample_rate=sample_rate, propagate_traces=False) @@ -225,6 +352,69 @@ def test_dynamic_sampling_head_sdk_creates_dsc( } +@pytest.mark.parametrize("sample_rate", [0.5, 1.0]) +def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( + sentry_init, capture_envelopes, sample_rate, monkeypatch +): + sentry_init( + traces_sample_rate=sample_rate, + release="foo", + _experiments={"trace_lifecycle": "stream"}, + ) + envelopes = capture_envelopes() + + # make sure transaction is sampled for both cases + with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=250000): + sentry_sdk.traces.new_trace() + segment = sentry_sdk.traces.start_span(name="Head SDK segment") + + baggage = segment._baggage + assert baggage is None + + with start_span(name="foo"): + pass + + # finish will create a new baggage entry + baggage = segment._baggage + trace_id = segment.trace_id + + assert baggage + assert not baggage.mutable + assert baggage.third_party_items == "" + assert baggage.sentry_items == { + "environment": "production", + "release": "foo", + "sample_rate": str(sample_rate), + "sampled": "true" if segment.sampled else "false", + "sample_rand": "0.250000", + "transaction": "Head SDK tx", + "trace_id": trace_id, + } + + expected_baggage = ( + f"sentry-trace_id={trace_id}," + "sentry-sample_rand=0.250000," + "sentry-environment=production," + "sentry-release=foo," + f"sentry-transaction=Head%%20SDK%%20tx," + f"sentry-sample_rate={sample_rate}," + f"sentry-sampled={'true' if segment.sampled else 'false'}" + ) + assert baggage.serialize() == expected_baggage + + (envelope,) = envelopes + assert envelope.headers["trace"] == baggage.dynamic_sampling_context() + assert envelope.headers["trace"] == { + "environment": "production", + "release": "foo", + "sample_rate": str(sample_rate), + "sample_rand": "0.250000", + "sampled": "true" if segment.sampled else "false", + "transaction": "Head SDK tx", + "trace_id": trace_id, + } + + @pytest.mark.parametrize( "args,expected_refcount", [({"traces_sample_rate": 1.0}, 100), ({"traces_sample_rate": 0.0}, 0)], @@ -254,6 +444,36 @@ def foo(): assert len(references) == expected_refcount +@pytest.mark.parametrize( + "args", + [{"traces_sample_rate": 1.0}, {"traces_sample_rate": 0.0}], +) +def test_memory_usage_span_streaming(sentry_init, capture_events, args): + sentry_init(**args, _experiments={"trace_lifecycle": "stream"}) + + references = weakref.WeakSet() + + with sentry_sdk.traces.start_span(name="hi"): + for i in range(100): + with sentry_sdk.traces.start_span(name=f"hi {i}") as span: + + def foo(): + pass + + references.add(foo) + span.set_attribute("foo", foo) + + sentry_sdk.flush() + + del foo + del span + + # required only for pypy (cpython frees immediately) + gc.collect() + + assert len(references) == 0 + + def test_transactions_do_not_go_through_before_send(sentry_init, capture_events): def before_send(event, hint): raise RuntimeError("should not be called") @@ -267,6 +487,25 @@ def before_send(event, hint): assert len(events) == 1 +def test_segments_do_not_go_through_before_send(sentry_init, capture_items): + def before_send(event, hint): + raise RuntimeError("should not be called") + + sentry_init( + traces_sample_rate=1.0, + before_send=before_send, + _experiments={"trace_lifecycle": "stream"}, + ) + items = capture_items() + + with sentry_sdk.traces.start_span(name="/"): + pass + + sentry_sdk.flush() + + assert len(items) == 1 + + def test_start_span_after_finish(sentry_init, capture_events): class CustomTransport(Transport): def capture_envelope(self, envelope): @@ -286,6 +525,33 @@ def capture_event(self, event): assert len(events) == 1 +def test_start_span_after_finish_span_streaming(sentry_init, capture_items): + class CustomTransport(Transport): + def capture_envelope(self, envelope): + with sentry_sdk.traces.start_span(name="toolate"): + pass + sentry_sdk.flush() + + def capture_event(self, event): + with sentry_sdk.traces.start_span(name="justdont"): + pass + sentry_sdk.flush() + + sentry_init( + traces_sample_rate=1, + transport=CustomTransport(), + _experiments={"trace_lifecycle": "stream"}, + ) + items = capture_items() + + with sentry_sdk.traces.start_span(name="hi"): + pass + + sentry_sdk.flush() + + assert len(items) == 1 + + def test_trace_propagation_meta_head_sdk(sentry_init): sentry_init(traces_sample_rate=1.0, release="foo") @@ -310,6 +576,35 @@ def test_trace_propagation_meta_head_sdk(sentry_init): assert baggage_content == transaction.get_baggage().serialize() +def test_trace_propagation_meta_head_sdk_span_streaming(sentry_init): + sentry_init( + traces_sample_rate=1.0, + release="foo", + _experiments={"trace_lifecycle": "stream"}, + ) + + sentry_sdk.traces.new_trace() + + meta = None + span = None + + with sentry_sdk.traces.start_span(name="Head SDK segment") as segment: + with sentry_sdk.traces.start_span(name="foo") as current_span: + span = current_span + meta = sentry_sdk.get_current_scope().trace_propagation_meta() + + ind = meta.find(">") + 1 + sentry_trace, baggage = meta[:ind], meta[ind:] + + assert 'meta name="sentry-trace"' in sentry_trace + sentry_trace_content = re.findall('content="([^"]*)"', sentry_trace)[0] + assert sentry_trace_content == span._to_traceparent() + + assert 'meta name="baggage"' in baggage + baggage_content = re.findall('content="([^"]*)"', baggage)[0] + assert baggage_content == segment._get_baggage().serialize() + + @pytest.mark.parametrize( "exception_cls,exception_value", [ @@ -338,6 +633,33 @@ def test_non_error_exceptions( assert event["contexts"]["trace"]["status"] == "ok" +@pytest.mark.parametrize( + "exception_cls,exception_value", + [ + (SystemExit, 0), + ], +) +def test_non_error_exceptions_span_streaming( + sentry_init, capture_items, exception_cls, exception_value +): + sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + items = capture_items() + + with sentry_sdk.traces.start_span(name="hi") as segment: + segment.status = SPANSTATUS.OK + with pytest.raises(exception_cls): + with sentry_sdk.traces.start_span(name="foo"): + raise exception_cls(exception_value) + + sentry_sdk.flush() + + assert len(items) == 2 + span1, span2 = [i.payload for i in items] + + assert span1["status"] == "ok" + assert span2["status"] == "ok" + + @pytest.mark.parametrize("exception_value", [None, 0, False]) def test_good_sysexit_doesnt_fail_transaction( sentry_init, capture_events, exception_value @@ -364,6 +686,30 @@ def test_good_sysexit_doesnt_fail_transaction( assert event["contexts"]["trace"]["status"] == "ok" +@pytest.mark.parametrize("exception_value", [None, 0, False]) +def test_good_sysexit_doesnt_fail_segment_span_streaming( + sentry_init, capture_items, exception_value +): + sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + items = capture_items() + + with sentry_sdk.traces.start_span(name="hi"): + with pytest.raises(SystemExit): + with sentry_sdk.traces.start_span(name="foo"): + if exception_value is not False: + sys.exit(exception_value) + else: + sys.exit() + + sentry_sdk.flush() + + assert len(items) == 2 + + span1, span2 = [i.payload for i in items] + assert span1["status"] == "ok" + assert span2["status"] == "ok" + + @pytest.mark.parametrize( "strict_trace_continuation,baggage_org_id,dsn_org_id,should_continue_trace", ( @@ -418,7 +764,68 @@ def test_continue_trace_strict_trace_continuation( == "771a43a4192642f0b136d5159a501700" ) assert transaction.parent_span_id != "1234567890abcdef" - assert not transaction.parent_sampled + assert transaction.parent_sampled is None + + +@pytest.mark.parametrize( + "strict_trace_continuation,baggage_org_id,dsn_org_id,should_continue_trace", + ( + (True, "sentry-org_id=1234", "o1234", True), + (True, "sentry-org_id=1234", "o9999", False), + (True, "sentry-org_id=9999", "o1234", False), + (False, "sentry-org_id=1234", "o1234", True), + (False, "sentry-org_id=9999", "o1234", False), + (False, "sentry-org_id=1234", "o9999", False), + (False, "sentry-org_id=1234", "not_org_id", True), + (False, "", "o1234", True), + ), +) +def test_continue_trace_strict_trace_continuation_span_streaming( + sentry_init, + strict_trace_continuation, + baggage_org_id, + dsn_org_id, + should_continue_trace, +): + sentry_init( + dsn=f"https://mysecret@{dsn_org_id}.ingest.sentry.io/12312012", + strict_trace_continuation=strict_trace_continuation, + traces_sample_rate=1.0, + transport=TestTransportWithOptions, + _experiments={"trace_lifecycle": "stream"}, + ) + + headers = { + "sentry-trace": "771a43a4192642f0b136d5159a501700-1234567890abcdef-1", + "baggage": ( + "other-vendor-value-1=foo;bar;baz," + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + f"{baggage_org_id}," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337," + "sentry-user_id=Am%C3%A9lie," + "other-vendor-value-2=foo;bar;" + ), + } + + sentry_sdk.traces.continue_trace(headers) + + with sentry_sdk.traces.start_span(name="strict trace") as segment: + headers = sentry_sdk.get_current_scope().iter_trace_propagation_headers(segment) + + if should_continue_trace: + assert segment.trace_id == "771a43a4192642f0b136d5159a501700" + assert segment._parent_span_id == "1234567890abcdef" + assert segment._parent_sampled is True + + else: + assert ( + segment.trace_id + != "771a43a4192642f0b136d5159a501700" + == "771a43a4192642f0b136d5159a501700" + ) + assert segment._parent_span_id != "1234567890abcdef" + assert segment._parent_sampled is None def test_continue_trace_forces_new_traces_when_no_propagation(sentry_init): @@ -430,3 +837,39 @@ def test_continue_trace_forces_new_traces_when_no_propagation(sentry_init): tx2 = continue_trace({}, name="tx2") assert tx1.trace_id != tx2.trace_id + + +def test_continue_trace_forces_new_traces_when_no_propagation_span_streaming( + sentry_init, +): + """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" + + sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + + sentry_sdk.traces.continue_trace({}) + with sentry_sdk.traces.start_span(name="segment1") as segment1: + pass + + sentry_sdk.traces.continue_trace({}) + with sentry_sdk.traces.start_span(name="segment2") as segment2: + pass + + assert segment1.trace_id != segment2.trace_id + + +def test_continue_trace_forces_new_traces_when_no_propagation_with_new_trace_span_streaming( + sentry_init, +): + """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" + + sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + + sentry_sdk.traces.new_trace() + with sentry_sdk.traces.start_span(name="segment1") as segment1: + pass + + sentry_sdk.traces.new_trace() + with sentry_sdk.traces.start_span(name="segment2") as segment2: + pass + + assert segment1.trace_id != segment2.trace_id From 1cec7815cfd8c22c2734e0dd88e3f75ef5d04030 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 9 Jul 2026 15:08:17 +0200 Subject: [PATCH 04/14] dont override source --- sentry_sdk/traces.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index 0131f694f1..71f718b494 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -581,7 +581,8 @@ def _set_segment_attributes(self) -> None: self.set_attribute( SPANDATA.SENTRY_SDK_INTEGRATIONS, sorted(client.integrations.keys()) ) - self.set_attribute("sentry.span.source", SegmentSource.CUSTOM.value) + if not self.get_attributes().get("sentry.span.source"): + self.set_attribute("sentry.span.source", SegmentSource.CUSTOM.value) if client.options.get("dist") and SPANDATA.SENTRY_DIST not in self._attributes: self.set_attribute( From 0926ee02c14e8181577eea7136bce6fad574a5ba Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Fri, 10 Jul 2026 09:58:43 +0200 Subject: [PATCH 05/14] fix --- tests/tracing/test_integration_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index d4b0b38206..f9a0fe1c1e 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -410,7 +410,7 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( "sample_rate": str(sample_rate), "sample_rand": "0.250000", "sampled": "true" if segment.sampled else "false", - "transaction": "Head SDK tx", + "transaction": "Head SDK segment", "trace_id": trace_id, } From 2931f32be624630a5bc3867057ed8dc282320c61 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 20 Jul 2026 13:40:35 +0200 Subject: [PATCH 06/14] . --- sentry_sdk/traces.py | 6 +++-- tests/tracing/test_integration_tests.py | 34 +++++++++++-------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index 71f718b494..b80dea9370 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -581,8 +581,10 @@ def _set_segment_attributes(self) -> None: self.set_attribute( SPANDATA.SENTRY_SDK_INTEGRATIONS, sorted(client.integrations.keys()) ) - if not self.get_attributes().get("sentry.span.source"): - self.set_attribute("sentry.span.source", SegmentSource.CUSTOM.value) + if not self.get_attributes().get("sentry.segment.name.source"): + self.set_attribute( + "sentry.segment.name.source", SegmentNameSource.CUSTOM.value + ) if client.options.get("dist") and SPANDATA.SENTRY_DIST not in self._attributes: self.set_attribute( diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index f9a0fe1c1e..0e8599fa24 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -78,7 +78,7 @@ def test_basic_span_streaming(sentry_init, capture_items, sample_rate): span1, span2, parent_span = [item.payload for item in items] assert parent_span["name"] == "hi" - assert parent_span["attributes"]["sentry.span.source"] == "custom" + assert parent_span["attributes"]["sentry.segment.name.source"] == "custom" assert span1["status"] == "error" assert span1["name"] == "foo" @@ -191,19 +191,20 @@ def test_continue_trace(sentry_init, capture_envelopes, parent_sampled, sample_r @pytest.mark.parametrize("parent_sampled", [True, False, None]) @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) def test_continue_trace_span_streaming( - sentry_init, capture_envelopes, parent_sampled, sample_rate + sentry_init, capture_items, parent_sampled, sample_rate ): """ Ensure data is actually passed along via headers, and that they are read correctly. """ sentry_init( - traces_sample_rate=sample_rate, _experiments={"trace_lifecycle": "stream"} + traces_sample_rate=sample_rate, + _experiments={"trace_lifecycle": "stream"}, ) - envelopes = capture_envelopes() + items = capture_items() # make a parent segment (normally this would be in a different service) - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.traces.start_span(name="hi", parent_span=None): with sentry_sdk.traces.start_span(name="hey") as old_span: headers = dict( sentry_sdk.get_current_scope().iter_trace_propagation_headers(old_span) @@ -245,25 +246,20 @@ def test_continue_trace_span_streaming( if parent_sampled is False or (sample_rate == 0 and parent_sampled is None): # in this case the child transaction won't be captured - trace1, message = envelopes - message_payload = message.get_event() - trace1_payload = trace1.items[0].payload.json + trace1, message = [item.payload for item in items] - assert trace1_payload["transaction"] == "hi" + assert trace1["transaction"] == "hi" else: - trace1, message, trace2 = envelopes - trace1_payload = trace1.items[0].payload.json - message_payload = message.get_event() - trace2_payload = trace2.items[0].payload.json + trace1, message, trace2 = [item.payload for item in items] - assert trace1_payload["attributes"]["sentry.segment.name"] == "hi" - assert trace2_payload["attributes"]["sentry.segment.name"] == "ho" + assert trace1["attributes"]["sentry.segment.name"] == "hi" + assert trace2["attributes"]["sentry.segment.name"] == "ho" assert ( - trace1_payload["trace_id"] - == trace2_payload["trace_id"] + trace1["trace_id"] + == trace2["trace_id"] == child_segment.trace_id - == message_payload["contexts"]["trace"]["trace_id"] + == message["contexts"]["trace"]["trace_id"] ) assert trace2.headers["trace"] == baggage.dynamic_sampling_context() @@ -275,7 +271,7 @@ def test_continue_trace_span_streaming( "sample_rate": str(sample_rate), } - assert message_payload["message"] == "hello" + assert message["message"] == "hello" @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) From 8cbbfea8aa478a53470997a2300d32c1cdbed497 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 09:32:20 +0200 Subject: [PATCH 07/14] fix(tests): Fix streaming span integration tests - Construct sentry-trace headers manually since StreamedSpan.sampled is always True, making it impossible to vary parent_sampled via real spans - Use context managers for streaming spans so they finish and get sent - Fix sampling condition to match streaming behavior (uses sample_rate/ sample_rand, not parent_sampled directly) - Update span name via span.name instead of scope.transaction - Fix copy-paste errors in DSC test (wrong transaction name, missing URL encoding) Co-Authored-By: Claude Opus 4.6 --- tests/tracing/test_integration_tests.py | 156 +++++++++++++++--------- 1 file changed, 95 insertions(+), 61 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 0e8599fa24..e425cbef36 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -87,8 +87,8 @@ def test_basic_span_streaming(sentry_init, capture_items, sample_rate): assert span2["status"] == "ok" assert span2["name"] == "bar" - assert span1["attributes"]["sentry.segment.id"] == parent_span["span_id"] - assert span1["attributes"]["sentry.segment.name"] == "hi" + assert span2["attributes"]["sentry.segment.id"] == parent_span["span_id"] + assert span2["attributes"]["sentry.segment.name"] == "hi" else: assert not items @@ -203,75 +203,108 @@ def test_continue_trace_span_streaming( ) items = capture_items() - # make a parent segment (normally this would be in a different service) - with sentry_sdk.traces.start_span(name="hi", parent_span=None): - with sentry_sdk.traces.start_span(name="hey") as old_span: - headers = dict( - sentry_sdk.get_current_scope().iter_trace_propagation_headers(old_span) - ) - headers["baggage"] = ( - "other-vendor-value-1=foo;bar;baz," - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337," - "sentry-user_id=Amelie," - "sentry-sample_rand=0.250000," - "other-vendor-value-2=foo;bar;" - ) + # Simulate incoming headers from another service. + # We construct the sentry-trace header manually because StreamedSpan.sampled + # is always True (and NoOpStreamedSpan.sampled is always False), so we can't + # vary parent_sampled by generating headers from a real span. + trace_id = "771a43a4192642f0b136d5159a501700" + parent_span_id = "1234567890abcdef" + + sampled_flag = "" + if parent_sampled is True: + sampled_flag = "-1" + elif parent_sampled is False: + sampled_flag = "-0" + + headers = { + "sentry-trace": f"{trace_id}-{parent_span_id}{sampled_flag}", + "baggage": ( + "other-vendor-value-1=foo;bar;baz," + f"sentry-trace_id={trace_id}," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337," + "sentry-user_id=Amelie," + "sentry-sample_rand=0.250000," + "other-vendor-value-2=foo;bar;" + ), + } # child segment, to prove that we can read 'sentry-trace' header data correctly sentry_sdk.traces.continue_trace(headers) - child_segment = sentry_sdk.traces.start_span(name="WRONG") - assert child_segment is not None - assert child_segment._parent_sampled == parent_sampled - assert child_segment.trace_id == old_span.trace_id - assert child_segment._parent_span_id == old_span.span_id - assert child_segment.span_id != old_span.span_id - - baggage = child_segment._baggage - assert baggage - assert not baggage.mutable - assert baggage.sentry_items == { - "public_key": "49d0f7386ad645858ae85020e393bef3", - "trace_id": "771a43a4192642f0b136d5159a501700", - "user_id": "Amelie", - "sample_rand": "0.250000", - "sample_rate": "0.01337", - } - # change the transaction name from "WRONG" to make sure the change - # is reflected in the final data - sentry_sdk.get_current_scope().transaction = "ho" - capture_message("hello") + with sentry_sdk.traces.start_span(name="WRONG") as child_segment: + assert child_segment is not None + assert child_segment._parent_sampled == parent_sampled + assert child_segment.trace_id == trace_id + assert child_segment._parent_span_id == parent_span_id + assert child_segment.span_id != parent_span_id + + baggage = child_segment._baggage + assert baggage + assert not baggage.mutable + + # When parent_sampled is None, the SDK falls back to the client's + # traces_sample_rate and _update_sample_rate mutates the baggage's + # sample_rate. When parent_sampled is set, the baggage sample_rate + # from the incoming header (0.01337) is used as-is. + if parent_sampled is not None: + expected_sample_rate = "0.01337" + else: + expected_sample_rate = str(sample_rate) + + assert baggage.sentry_items == { + "public_key": "49d0f7386ad645858ae85020e393bef3", + "trace_id": trace_id, + "user_id": "Amelie", + "sample_rand": "0.250000", + "sample_rate": expected_sample_rate, + } - if parent_sampled is False or (sample_rate == 0 and parent_sampled is None): - # in this case the child transaction won't be captured - trace1, message = [item.payload for item in items] + # change the segment name from "WRONG" to make sure the change + # is reflected in the final data + child_segment.name = "ho" + capture_message("hello") - assert trace1["transaction"] == "hi" + sentry_sdk.flush() + + # In streaming mode, sampling uses sample_rate and sample_rand, not + # parent_sampled directly. With baggage sample_rate=0.01337 and + # sample_rand=0.250000, the child is only sampled when parent_sampled + # is None (falls back to client's traces_sample_rate) and that rate > 0. + child_sampled = parent_sampled is None and sample_rate > 0 + + if not child_sampled: + # the child segment won't be captured + messages = [item for item in items if item.type != "span"] + assert len(messages) == 1 + assert messages[0].payload["message"] == "hello" else: - trace1, message, trace2 = [item.payload for item in items] + spans = [item for item in items if item.type == "span"] + messages = [item for item in items if item.type != "span"] + + assert len(spans) == 1 + assert len(messages) == 1 + + child_span_payload = spans[0].payload + message_payload = messages[0].payload - assert trace1["attributes"]["sentry.segment.name"] == "hi" - assert trace2["attributes"]["sentry.segment.name"] == "ho" + assert child_span_payload["attributes"]["sentry.segment.name"] == "ho" assert ( - trace1["trace_id"] - == trace2["trace_id"] + child_span_payload["trace_id"] == child_segment.trace_id - == message["contexts"]["trace"]["trace_id"] + == message_payload["contexts"]["trace"]["trace_id"] ) - assert trace2.headers["trace"] == baggage.dynamic_sampling_context() - assert trace2.headers["trace"] == { + assert baggage.dynamic_sampling_context() == { "public_key": "49d0f7386ad645858ae85020e393bef3", - "trace_id": "771a43a4192642f0b136d5159a501700", + "trace_id": trace_id, "user_id": "Amelie", "sample_rand": "0.250000", "sample_rate": str(sample_rate), } - assert message["message"] == "hello" + assert message_payload["message"] == "hello" @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) @@ -359,18 +392,19 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( ) envelopes = capture_envelopes() - # make sure transaction is sampled for both cases + # make sure segment is sampled for both cases with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=250000): sentry_sdk.traces.new_trace() - segment = sentry_sdk.traces.start_span(name="Head SDK segment") + with sentry_sdk.traces.start_span(name="Head SDK segment") as segment: + baggage = segment._baggage + assert baggage is None - baggage = segment._baggage - assert baggage is None + with sentry_sdk.traces.start_span(name="foo"): + pass - with start_span(name="foo"): - pass + sentry_sdk.flush() - # finish will create a new baggage entry + # flush triggers the batcher which populates _baggage via _get_baggage() baggage = segment._baggage trace_id = segment.trace_id @@ -383,7 +417,7 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( "sample_rate": str(sample_rate), "sampled": "true" if segment.sampled else "false", "sample_rand": "0.250000", - "transaction": "Head SDK tx", + "transaction": "Head SDK segment", "trace_id": trace_id, } @@ -392,7 +426,7 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( "sentry-sample_rand=0.250000," "sentry-environment=production," "sentry-release=foo," - f"sentry-transaction=Head%%20SDK%%20tx," + "sentry-transaction=Head%20SDK%20segment," f"sentry-sample_rate={sample_rate}," f"sentry-sampled={'true' if segment.sampled else 'false'}" ) From 28e3f30fdab1250d199293b640e91088eeb6774f Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 11:57:20 +0200 Subject: [PATCH 08/14] use top level opt --- tests/tracing/test_integration_tests.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index e425cbef36..7abeb5cb37 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -199,7 +199,7 @@ def test_continue_trace_span_streaming( """ sentry_init( traces_sample_rate=sample_rate, - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) items = capture_items() @@ -388,7 +388,7 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( sentry_init( traces_sample_rate=sample_rate, release="foo", - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) envelopes = capture_envelopes() @@ -479,7 +479,7 @@ def foo(): [{"traces_sample_rate": 1.0}, {"traces_sample_rate": 0.0}], ) def test_memory_usage_span_streaming(sentry_init, capture_events, args): - sentry_init(**args, _experiments={"trace_lifecycle": "stream"}) + sentry_init(**args, trace_lifecycle="stream") references = weakref.WeakSet() @@ -524,7 +524,7 @@ def before_send(event, hint): sentry_init( traces_sample_rate=1.0, before_send=before_send, - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) items = capture_items() @@ -570,7 +570,7 @@ def capture_event(self, event): sentry_init( traces_sample_rate=1, transport=CustomTransport(), - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) items = capture_items() @@ -610,7 +610,7 @@ def test_trace_propagation_meta_head_sdk_span_streaming(sentry_init): sentry_init( traces_sample_rate=1.0, release="foo", - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) sentry_sdk.traces.new_trace() @@ -672,7 +672,7 @@ def test_non_error_exceptions( def test_non_error_exceptions_span_streaming( sentry_init, capture_items, exception_cls, exception_value ): - sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items() with sentry_sdk.traces.start_span(name="hi") as segment: @@ -720,7 +720,7 @@ def test_good_sysexit_doesnt_fail_transaction( def test_good_sysexit_doesnt_fail_segment_span_streaming( sentry_init, capture_items, exception_value ): - sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items() with sentry_sdk.traces.start_span(name="hi"): @@ -822,7 +822,7 @@ def test_continue_trace_strict_trace_continuation_span_streaming( strict_trace_continuation=strict_trace_continuation, traces_sample_rate=1.0, transport=TestTransportWithOptions, - _experiments={"trace_lifecycle": "stream"}, + trace_lifecycle="stream", ) headers = { @@ -874,7 +874,7 @@ def test_continue_trace_forces_new_traces_when_no_propagation_span_streaming( ): """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" - sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") sentry_sdk.traces.continue_trace({}) with sentry_sdk.traces.start_span(name="segment1") as segment1: @@ -892,7 +892,7 @@ def test_continue_trace_forces_new_traces_when_no_propagation_with_new_trace_spa ): """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" - sentry_init(traces_sample_rate=1.0, _experiments={"trace_lifecycle": "stream"}) + sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") sentry_sdk.traces.new_trace() with sentry_sdk.traces.start_span(name="segment1") as segment1: From e42025b8a7cb172b1e7e1fa895fc0e413a806def Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 12:30:14 +0200 Subject: [PATCH 09/14] . --- tests/tracing/test_integration_tests.py | 31 +++++++++++-------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 7abeb5cb37..29b2b52c38 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -203,18 +203,19 @@ def test_continue_trace_span_streaming( ) items = capture_items() - # Simulate incoming headers from another service. - # We construct the sentry-trace header manually because StreamedSpan.sampled - # is always True (and NoOpStreamedSpan.sampled is always False), so we can't - # vary parent_sampled by generating headers from a real span. + # Simulate incoming headers from another service trace_id = "771a43a4192642f0b136d5159a501700" parent_span_id = "1234567890abcdef" - sampled_flag = "" if parent_sampled is True: sampled_flag = "-1" + parent_sample_rate = "0.5" elif parent_sampled is False: sampled_flag = "-0" + parent_sample_rate = "0.001" + elif parent_sampled is None: + sampled_flag = "" + parent_sample_rate = "0.001" headers = { "sentry-trace": f"{trace_id}-{parent_span_id}{sampled_flag}", @@ -222,16 +223,16 @@ def test_continue_trace_span_streaming( "other-vendor-value-1=foo;bar;baz," f"sentry-trace_id={trace_id}," "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337," + f"sentry-sample_rate={parent_sample_rate}," "sentry-user_id=Amelie," "sentry-sample_rand=0.250000," "other-vendor-value-2=foo;bar;" ), } - # child segment, to prove that we can read 'sentry-trace' header data correctly sentry_sdk.traces.continue_trace(headers) + # child segment, to prove that we can read 'sentry-trace' header data correctly with sentry_sdk.traces.start_span(name="WRONG") as child_segment: assert child_segment is not None assert child_segment._parent_sampled == parent_sampled @@ -243,14 +244,10 @@ def test_continue_trace_span_streaming( assert baggage assert not baggage.mutable - # When parent_sampled is None, the SDK falls back to the client's - # traces_sample_rate and _update_sample_rate mutates the baggage's - # sample_rate. When parent_sampled is set, the baggage sample_rate - # from the incoming header (0.01337) is used as-is. if parent_sampled is not None: - expected_sample_rate = "0.01337" + expected_sample_rate = str(float(parent_sampled)) else: - expected_sample_rate = str(sample_rate) + expected_sample_rate = parent_sample_rate assert baggage.sentry_items == { "public_key": "49d0f7386ad645858ae85020e393bef3", @@ -267,11 +264,9 @@ def test_continue_trace_span_streaming( sentry_sdk.flush() - # In streaming mode, sampling uses sample_rate and sample_rand, not - # parent_sampled directly. With baggage sample_rate=0.01337 and - # sample_rand=0.250000, the child is only sampled when parent_sampled - # is None (falls back to client's traces_sample_rate) and that rate > 0. - child_sampled = parent_sampled is None and sample_rate > 0 + child_sampled = parent_sampled is True or ( + parent_sampled is None and sample_rate > 0 + ) if not child_sampled: # the child segment won't be captured From 2092b87e8fa87db14bf7733488afe70bb3adadbb Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 12:48:09 +0200 Subject: [PATCH 10/14] fixes --- tests/tracing/test_integration_tests.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 29b2b52c38..763d112d26 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -247,7 +247,10 @@ def test_continue_trace_span_streaming( if parent_sampled is not None: expected_sample_rate = str(float(parent_sampled)) else: - expected_sample_rate = parent_sample_rate + if sample_rate is None: + expected_sample_rate = parent_sample_rate + else: + expected_sample_rate = str(sample_rate) assert baggage.sentry_items == { "public_key": "49d0f7386ad645858ae85020e393bef3", @@ -291,12 +294,20 @@ def test_continue_trace_span_streaming( == message_payload["contexts"]["trace"]["trace_id"] ) + if parent_sampled is not None: + expected_sample_rate = str(float(parent_sampled)) + else: + if sample_rate is None: + expected_sample_rate = parent_sample_rate + else: + expected_sample_rate = str(sample_rate) + assert baggage.dynamic_sampling_context() == { "public_key": "49d0f7386ad645858ae85020e393bef3", "trace_id": trace_id, "user_id": "Amelie", "sample_rand": "0.250000", - "sample_rate": str(sample_rate), + "sample_rate": expected_sample_rate, } assert message_payload["message"] == "hello" From 9bcaf4a015069cdb1b0bfa7fee89b8cdec9551de Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 13:10:19 +0200 Subject: [PATCH 11/14] . --- tests/tracing/test_integration_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 763d112d26..90f1e1e44c 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -410,7 +410,6 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( sentry_sdk.flush() - # flush triggers the batcher which populates _baggage via _get_baggage() baggage = segment._baggage trace_id = segment.trace_id From 8e2714af587dee3164f8356fa792fb52b816fa59 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 13:13:38 +0200 Subject: [PATCH 12/14] wtf --- tests/tracing/test_integration_tests.py | 29 +++++++++---------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 90f1e1e44c..ca89b2199a 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -775,29 +775,24 @@ def test_continue_trace_strict_trace_continuation( headers = { "sentry-trace": "771a43a4192642f0b136d5159a501700-1234567890abcdef-1", "baggage": ( - "other-vendor-value-1=foo;bar;baz, sentry-trace_id=771a43a4192642f0b136d5159a501700, " - f"{baggage_org_id}, " - "sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, " - "sentry-user_id=Am%C3%A9lie, other-vendor-value-2=foo;bar;" + "other-vendor-value-1=foo;bar;baz," + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + f"{baggage_org_id}," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=0.01337," + "sentry-user_id=Am%C3%A9lie," + "other-vendor-value-2=foo;bar;" ), } transaction = continue_trace(headers, name="strict trace") if should_continue_trace: - assert ( - transaction.trace_id - == "771a43a4192642f0b136d5159a501700" - == "771a43a4192642f0b136d5159a501700" - ) + assert transaction.trace_id == "771a43a4192642f0b136d5159a501700" assert transaction.parent_span_id == "1234567890abcdef" assert transaction.parent_sampled else: - assert ( - transaction.trace_id - != "771a43a4192642f0b136d5159a501700" - == "771a43a4192642f0b136d5159a501700" - ) + assert transaction.trace_id != "771a43a4192642f0b136d5159a501700" assert transaction.parent_span_id != "1234567890abcdef" assert transaction.parent_sampled is None @@ -854,11 +849,7 @@ def test_continue_trace_strict_trace_continuation_span_streaming( assert segment._parent_sampled is True else: - assert ( - segment.trace_id - != "771a43a4192642f0b136d5159a501700" - == "771a43a4192642f0b136d5159a501700" - ) + assert segment.trace_id != "771a43a4192642f0b136d5159a501700" assert segment._parent_span_id != "1234567890abcdef" assert segment._parent_sampled is None From d8051cc17ad41bb8ca398a10b67a16edcc4d8413 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 13:15:15 +0200 Subject: [PATCH 13/14] . --- tests/tracing/test_integration_tests.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index ca89b2199a..a7d59d2741 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -886,8 +886,6 @@ def test_continue_trace_forces_new_traces_when_no_propagation_span_streaming( def test_continue_trace_forces_new_traces_when_no_propagation_with_new_trace_span_streaming( sentry_init, ): - """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") sentry_sdk.traces.new_trace() From 31d8a8310c93f59ef9a79dc11fec9f946d7156a0 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 23 Jul 2026 14:16:42 +0200 Subject: [PATCH 14/14] . --- tests/tracing/test_span_streaming.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tracing/test_span_streaming.py b/tests/tracing/test_span_streaming.py index 6b155e4a45..4a984ecf78 100644 --- a/tests/tracing/test_span_streaming.py +++ b/tests/tracing/test_span_streaming.py @@ -1814,6 +1814,7 @@ def test_default_attributes(sentry_init, capture_envelopes): "sentry.origin": {"value": "manual", "type": "string"}, "sentry.sdk.integrations": {"value": mock.ANY, "type": "array"}, "sentry.trace_lifecycle": {"value": "stream", "type": "string"}, + "sentry.segment.name.source": {"value": "custom", "type": "string"}, "process.runtime.name": { "type": "string", "value": mock.ANY,