Skip to content

Commit bb757f4

Browse files
committed
unpack aiohttp request
1 parent e8c1813 commit bb757f4

File tree

3 files changed

+58
-25
lines changed

3 files changed

+58
-25
lines changed

sentry_sdk/integrations/aiohttp.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@
6565

6666
TRANSACTION_STYLE_VALUES = ("handler_name", "method_and_path_pattern")
6767

68+
REQUEST_PROPERTY_TO_ATTRIBUTE = {
69+
"query_string": "url.query",
70+
"method": "http.request.method",
71+
"scheme": "url.scheme",
72+
"path": "url.path",
73+
}
74+
6875

6976
class AioHttpIntegration(Integration):
7077
identifier = "aiohttp"
@@ -127,19 +134,19 @@ async def sentry_app_handle(self, request, *args, **kwargs):
127134

128135
headers = dict(request.headers)
129136
with sentry_sdk.continue_trace(headers):
130-
with sentry_sdk.start_transaction(
137+
with sentry_sdk.start_span(
131138
op=OP.HTTP_SERVER,
132139
# If this transaction name makes it to the UI, AIOHTTP's
133140
# URL resolver did not find a route or died trying.
134141
name="generic AIOHTTP request",
135142
source=TRANSACTION_SOURCE_ROUTE,
136143
origin=AioHttpIntegration.origin,
137-
custom_sampling_context={"aiohttp_request": request},
138-
) as transaction:
144+
attributes=_prepopulate_attributes(request),
145+
) as span:
139146
try:
140147
response = await old_handle(self, request)
141148
except HTTPException as e:
142-
transaction.set_http_status(e.status_code)
149+
span.set_http_status(e.status_code)
143150

144151
if (
145152
e.status_code
@@ -149,14 +156,14 @@ async def sentry_app_handle(self, request, *args, **kwargs):
149156

150157
raise
151158
except (asyncio.CancelledError, ConnectionResetError):
152-
transaction.set_status(SPANSTATUS.CANCELLED)
159+
span.set_status(SPANSTATUS.CANCELLED)
153160
raise
154161
except Exception:
155162
# This will probably map to a 500 but seems like we
156163
# have no way to tell. Do not set span status.
157164
reraise(*_capture_exception())
158165

159-
transaction.set_http_status(response.status)
166+
span.set_http_status(response.status)
160167
return response
161168

162169
Application._handle = sentry_app_handle
@@ -363,3 +370,29 @@ def get_aiohttp_request_data(request):
363370

364371
# request has no body
365372
return None
373+
374+
375+
def _prepopulate_attributes(request):
376+
# type: (Request) -> dict[str, Any]
377+
"""Construct initial span attributes that can be used in traces sampler."""
378+
attributes = {}
379+
380+
for prop, attr in REQUEST_PROPERTY_TO_ATTRIBUTE.items():
381+
if getattr(request, prop, None) is not None:
382+
attributes[attr] = getattr(request, prop)
383+
384+
try:
385+
host, port = request.host.split(":")
386+
attributes["server.address"] = host
387+
attributes["server.port"] = port
388+
except ValueError:
389+
attributes["server.address"] = request.host
390+
391+
try:
392+
url = f"{request.scheme}: //{request.host}{request.path}"
393+
if request.query_string:
394+
attributes["url.full"] = f"{url}?{request.query_string}"
395+
except Exception:
396+
pass
397+
398+
return attributes

sentry_sdk/integrations/opentelemetry/sampler.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ def should_sample(
153153
}
154154
sampling_context.update(attributes)
155155
sample_rate = client.options["traces_sampler"](sampling_context)
156-
157156
else:
158157
# Check if there is a parent with a sampling decision
159158
parent_sampled = get_parent_sampled(parent_span_context, trace_id)

tests/integrations/aiohttp/test_aiohttp.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import asyncio
22
import json
3+
import re
34
from contextlib import suppress
45
from unittest import mock
56

67
import pytest
78
from aiohttp import web, ClientSession
89
from aiohttp.client import ServerDisconnectedError
9-
from aiohttp.web_request import Request
1010
from aiohttp.web_exceptions import (
1111
HTTPInternalServerError,
1212
HTTPNetworkAuthenticationRequired,
@@ -291,13 +291,12 @@ async def hello(request):
291291

292292

293293
@pytest.mark.asyncio
294-
async def test_traces_sampler_gets_request_object_in_sampling_context(
294+
async def test_traces_sampler_gets_attributes_in_sampling_context(
295295
sentry_init,
296296
aiohttp_client,
297-
DictionaryContaining, # noqa: N803
298-
ObjectDescribedBy, # noqa: N803
299297
):
300-
traces_sampler = mock.Mock()
298+
traces_sampler = mock.Mock(return_value=True)
299+
301300
sentry_init(
302301
integrations=[AioHttpIntegration()],
303302
traces_sampler=traces_sampler,
@@ -310,17 +309,20 @@ async def kangaroo_handler(request):
310309
app.router.add_get("/tricks/kangaroo", kangaroo_handler)
311310

312311
client = await aiohttp_client(app)
313-
await client.get("/tricks/kangaroo")
312+
await client.get("/tricks/kangaroo?jump=high")
314313

315-
traces_sampler.assert_any_call(
316-
DictionaryContaining(
317-
{
318-
"aiohttp_request": ObjectDescribedBy(
319-
type=Request, attrs={"method": "GET", "path": "/tricks/kangaroo"}
320-
)
321-
}
322-
)
314+
assert traces_sampler.call_count == 1
315+
sampling_context = traces_sampler.call_args.args[0]
316+
assert re.match(
317+
r"http:\/\/127\.0\.0\.1:[0-9]{4,5}\/tricks\/kangaroo\?jump=high",
318+
sampling_context["url.full"],
323319
)
320+
assert sampling_context["url.path"] == "/tricks/kangaroo"
321+
assert sampling_context["url.query"] == "jump=high"
322+
assert sampling_context["url.scheme"] == "http"
323+
assert sampling_context["http.request.method"] == "GET"
324+
assert sampling_context["server.address"] == "127.0.0.1"
325+
assert sampling_context["server.port"].isnumeric()
324326

325327

326328
@pytest.mark.asyncio
@@ -574,17 +576,16 @@ async def handler(request):
574576
client = await aiohttp_client(raw_server)
575577
resp = await client.get("/", headers={"bagGage": "custom=value"})
576578

577-
assert (
578-
sorted(resp.request_info.headers["baggage"].split(","))
579-
== sorted([
579+
assert sorted(resp.request_info.headers["baggage"].split(",")) == sorted(
580+
[
580581
"custom=value",
581582
f"sentry-trace_id={transaction.trace_id}",
582583
"sentry-environment=production",
583584
"sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42",
584585
"sentry-transaction=/interactions/other-dogs/new-dog",
585586
"sentry-sample_rate=1.0",
586587
"sentry-sampled=true",
587-
])
588+
]
588589
)
589590

590591

0 commit comments

Comments
 (0)