Skip to content

Commit 72a7248

Browse files
authored
fix(asgi): Add url.path to ASGI request span attributes (#6652)
The ASGI integration was not setting `url.path` on streamed request spans. Add it by combining `root_path` and `path` from the ASGI scope, which correctly handles sub-mounted apps where `root_path` is non-empty. Fixes PY-2551 Fixes #6651
1 parent 07451d6 commit 72a7248

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

sentry_sdk/integrations/_asgi_common.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ def _get_request_attributes(asgi_scope: "Any") -> "dict[str, Any]":
135135
if query_string is not None
136136
else url_without_query_string
137137
)
138+
attributes["url.path"] = asgi_scope.get("root_path", "") + asgi_scope.get(
139+
"path", ""
140+
)
138141

139142
client = asgi_scope.get("client")
140143
if client and should_send_default_pii():

tests/integrations/asgi/test_asgi.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ async def test_capture_transaction(
221221
span["attributes"]["url.full"]
222222
== "http://localhost/some_url?somevalue=123"
223223
)
224+
assert span["attributes"]["url.path"] == "/some_url"
224225
assert span["attributes"]["http.query"] == "somevalue=123"
225226

226227
else:
@@ -242,6 +243,30 @@ async def test_capture_transaction(
242243
}
243244

244245

246+
@pytest.mark.asyncio
247+
async def test_capture_transaction_with_root_path(
248+
sentry_init,
249+
asgi3_app,
250+
capture_items,
251+
):
252+
sentry_init(
253+
send_default_pii=True,
254+
traces_sample_rate=1.0,
255+
_experiments={"trace_lifecycle": "stream"},
256+
)
257+
app = SentryAsgiMiddleware(asgi3_app)
258+
259+
async with TestClient(app, scope={"root_path": "/api"}) as client:
260+
items = capture_items("span")
261+
await client.get("/some_url")
262+
263+
sentry_sdk.flush()
264+
265+
assert len(items) == 1
266+
span = items[0].payload
267+
assert span["attributes"]["url.path"] == "/api/some_url"
268+
269+
245270
@pytest.mark.asyncio
246271
@pytest.mark.parametrize(
247272
"span_streaming",

tests/integrations/quart/test_quart.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ async def test_span_streaming_request_attributes_no_pii(sentry_init, capture_ite
822822
assert "http.request.header.host" in segment["attributes"]
823823

824824
assert "url.full" not in segment["attributes"]
825+
assert "url.path" not in segment["attributes"]
825826
assert "url.query" not in segment["attributes"]
826827
assert "client.address" not in segment["attributes"]
827828
assert "user.ip_address" not in segment["attributes"]
@@ -854,6 +855,7 @@ async def test_span_streaming_request_attributes_with_pii(sentry_init, capture_i
854855
assert (
855856
segment["attributes"]["url.full"] == "http://localhost/message?foo=bar&baz=qux"
856857
)
858+
assert segment["attributes"]["url.path"] == "/message"
857859
assert segment["attributes"]["url.query"] == "foo=bar&baz=qux"
858860
assert "client.address" in segment["attributes"]
859861
assert "user.ip_address" in segment["attributes"]

0 commit comments

Comments
 (0)