diff --git a/sentry_sdk/integrations/httpx.py b/sentry_sdk/integrations/httpx.py index e84a28d165..04db5047b4 100644 --- a/sentry_sdk/integrations/httpx.py +++ b/sentry_sdk/integrations/httpx.py @@ -1,6 +1,7 @@ from sentry_sdk import Hub from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import Integration, DidNotEnable +from sentry_sdk.tracing import BAGGAGE_HEADER_NAME from sentry_sdk.tracing_utils import should_propagate_trace from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, @@ -72,7 +73,13 @@ def send(self, request, **kwargs): key=key, value=value, url=request.url ) ) - request.headers[key] = value + if key == BAGGAGE_HEADER_NAME and request.headers.get( + BAGGAGE_HEADER_NAME + ): + # do not overwrite any existing baggage, just append to it + request.headers[key] += "," + value + else: + request.headers[key] = value rv = real_send(self, request, **kwargs) @@ -119,7 +126,13 @@ async def send(self, request, **kwargs): key=key, value=value, url=request.url ) ) - request.headers[key] = value + if key == BAGGAGE_HEADER_NAME and request.headers.get( + BAGGAGE_HEADER_NAME + ): + # do not overwrite any existing baggage, just append to it + request.headers[key] += "," + value + else: + request.headers[key] = value rv = await real_send(self, request, **kwargs) diff --git a/tests/integrations/httpx/test_httpx.py b/tests/integrations/httpx/test_httpx.py index 72188a23e3..ab1ee0b8a5 100644 --- a/tests/integrations/httpx/test_httpx.py +++ b/tests/integrations/httpx/test_httpx.py @@ -89,6 +89,46 @@ def test_outgoing_trace_headers(sentry_init, httpx_client): ) +@pytest.mark.parametrize( + "httpx_client", + (httpx.Client(), httpx.AsyncClient()), +) +def test_outgoing_trace_headers_append_to_baggage(sentry_init, httpx_client): + sentry_init( + traces_sample_rate=1.0, + integrations=[HttpxIntegration()], + release="d08ebdb9309e1b004c6f52202de58a09c2268e42", + ) + + url = "http://example.com/" + responses.add(responses.GET, url, status=200) + + with start_transaction( + name="/interactions/other-dogs/new-dog", + op="greeting.sniff", + trace_id="01234567890123456789012345678901", + ) as transaction: + if asyncio.iscoroutinefunction(httpx_client.get): + response = asyncio.get_event_loop().run_until_complete( + httpx_client.get(url, headers={"baGGage": "custom-data"}) + ) + else: + response = httpx_client.get(url, headers={"baGGage": "custom-data"}) + + request_span = transaction._span_recorder.spans[-1] + assert response.request.headers[ + "sentry-trace" + ] == "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=transaction.trace_id, + parent_span_id=request_span.span_id, + sampled=1, + ) + assert ( + response.request.headers["baggage"] + == "custom-data,sentry-trace_id=01234567890123456789012345678901,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0" + ) + + @pytest.mark.parametrize( "httpx_client,trace_propagation_targets,url,trace_propagated", [