Skip to content

Commit d9deb29

Browse files
committed
Changes after doing a review
1 parent b356795 commit d9deb29

2 files changed

Lines changed: 55 additions & 54 deletions

File tree

sentry_sdk/integrations/aiohttp.py

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,28 @@
44

55
import sentry_sdk
66
from sentry_sdk.api import continue_trace
7-
from sentry_sdk.consts import OP, SPANSTATUS, SPANDATA
7+
from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS
88
from sentry_sdk.integrations import (
99
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
10-
_check_minimum_version,
11-
Integration,
1210
DidNotEnable,
11+
Integration,
12+
_check_minimum_version,
1313
)
14-
from sentry_sdk.integrations.logging import ignore_logger
15-
from sentry_sdk.scope import should_send_default_pii
16-
from sentry_sdk.sessions import track_session
1714
from sentry_sdk.integrations._wsgi_common import (
1815
_filter_headers,
1916
request_body_within_bounds,
2017
)
18+
from sentry_sdk.integrations.logging import ignore_logger
19+
from sentry_sdk.scope import should_send_default_pii
20+
from sentry_sdk.sessions import track_session
21+
from sentry_sdk.traces import (
22+
SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE,
23+
)
2124
from sentry_sdk.traces import (
2225
NoOpStreamedSpan,
2326
SegmentSource,
2427
SpanStatus,
2528
StreamedSpan,
26-
SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE,
2729
)
2830
from sentry_sdk.tracing import (
2931
BAGGAGE_HEADER_NAME,
@@ -36,6 +38,10 @@
3638
should_propagate_trace,
3739
)
3840
from sentry_sdk.utils import (
41+
CONTEXTVARS_ERROR_MESSAGE,
42+
HAS_REAL_CONTEXTVARS,
43+
SENSITIVE_DATA_SUBSTITUTE,
44+
AnnotatedValue,
3945
capture_internal_exceptions,
4046
ensure_integration_enabled,
4147
event_from_exception,
@@ -44,39 +50,31 @@
4450
parse_version,
4551
reraise,
4652
transaction_from_function,
47-
HAS_REAL_CONTEXTVARS,
48-
CONTEXTVARS_ERROR_MESSAGE,
49-
SENSITIVE_DATA_SUBSTITUTE,
50-
AnnotatedValue,
5153
)
5254

5355
try:
5456
import asyncio
5557

56-
from aiohttp import __version__ as AIOHTTP_VERSION
5758
from aiohttp import ClientSession, TraceConfig
59+
from aiohttp import __version__ as AIOHTTP_VERSION
5860
from aiohttp.web import Application, HTTPException, UrlDispatcher
5961
except ImportError:
6062
raise DidNotEnable("AIOHTTP not installed")
6163

6264
from typing import TYPE_CHECKING
6365

6466
if TYPE_CHECKING:
65-
from aiohttp.web_request import Request
66-
from aiohttp.web_urldispatcher import UrlMappingMatchInfo
67-
from aiohttp import TraceRequestStartParams, TraceRequestEndParams
68-
6967
from collections.abc import Set
7068
from types import SimpleNamespace
71-
from typing import Any
72-
from typing import ContextManager
73-
from typing import Optional
74-
from typing import Tuple
75-
from typing import Union
69+
from typing import Any, ContextManager, Optional, Tuple, Union
70+
71+
from aiohttp import TraceRequestEndParams, TraceRequestStartParams
72+
from aiohttp.web_request import Request
73+
from aiohttp.web_urldispatcher import UrlMappingMatchInfo
7674

75+
from sentry_sdk._types import Attributes, Event, EventProcessor
7776
from sentry_sdk.tracing import Span
7877
from sentry_sdk.utils import ExcInfo
79-
from sentry_sdk._types import Attributes, Event, EventProcessor
8078

8179

8280
TRANSACTION_STYLE_VALUES = ("handler_name", "method_and_path_pattern")
@@ -145,22 +143,24 @@ async def sentry_app_handle(
145143
{"aiohttp_request": request}
146144
)
147145

148-
header_dict: "dict[str, Any]" = {}
146+
header_attributes: "dict[str, Any]" = {}
149147
for header, header_value in _filter_headers(
150148
headers, use_annotated_value=False
151149
).items():
152-
header_dict[f"http.request.header.{header.lower()}"] = (
150+
header_attributes[
151+
f"http.request.header.{header.lower()}"
152+
] = (
153153
# header_value will always be a string because we set `use_annotated_value` to false above
154154
header_value
155155
)
156156

157-
url_query = (
157+
url_query_attribute = (
158158
{"url.query": request.query_string}
159159
if request.query_string
160160
else {}
161161
)
162162

163-
client_address = (
163+
client_address_attributes = (
164164
{
165165
"client.address": request.remote,
166166
"user.ip_address": request.remote,
@@ -180,9 +180,9 @@ async def sentry_app_handle(
180180
"url.full": "%s://%s%s"
181181
% (request.scheme, request.host, request.path),
182182
"http.request.method": request.method,
183-
**url_query,
184-
**client_address,
185-
**header_dict,
183+
**url_query_attribute,
184+
**client_address_attributes,
185+
**header_attributes,
186186
},
187187
)
188188
else:
@@ -212,8 +212,8 @@ async def sentry_app_handle(
212212
"http.response.status_code", e.status_code
213213
)
214214

215-
# There are a number of sub-exceptions that should have an "ok" status, but will
216-
# actually have a status of error once the `raise` happens below
215+
# There are a number of sub-exceptions that should have an "ok" status,
216+
# but will actually have a status of error once the `raise` happens below
217217
# and we pass through the `should_be_treated_as_error` method invoked
218218
# within a span's `__exit__` method.
219219
#
@@ -224,6 +224,8 @@ async def sentry_app_handle(
224224
# approach as well, so this matches what we do today.
225225
span.status = SpanStatus.ERROR.value
226226
else:
227+
# Since a NoOpStreamedSpan can end up here, we have to guard against it
228+
# so this only gets set in the legacy transaction approach.
227229
if not isinstance(span, NoOpStreamedSpan):
228230
span.set_http_status(e.status_code)
229231

tests/integrations/aiohttp/test_aiohttp.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
1-
import os
2-
import datetime
31
import asyncio
2+
import datetime
43
import json
5-
4+
import os
65
from contextlib import suppress
76
from unittest import mock
87

98
import pytest
10-
119
from aiohttp import web
1210
from aiohttp.client import ServerDisconnectedError
13-
from aiohttp.web_request import Request
1411
from aiohttp.web_exceptions import (
12+
HTTPBadRequest,
1513
HTTPInternalServerError,
1614
HTTPNetworkAuthenticationRequired,
17-
HTTPBadRequest,
1815
HTTPNotFound,
1916
HTTPUnavailableForLegalReasons,
2017
)
18+
from aiohttp.web_request import Request
2119

2220
import sentry_sdk
2321
from sentry_sdk import capture_message, start_transaction
22+
from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE
2423
from sentry_sdk.consts import SPANDATA
25-
from sentry_sdk.integrations.aiohttp import AioHttpIntegration, create_trace_config
24+
from sentry_sdk.integrations.aiohttp import (
25+
BODY_NOT_READ_MESSAGE,
26+
AioHttpIntegration,
27+
create_trace_config,
28+
)
2629
from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE
2730
from tests.conftest import ApproxDict
28-
from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE
2931

3032

3133
@pytest.mark.asyncio
@@ -1317,17 +1319,15 @@ async def hello(request):
13171319
# test the segment is the aiohttp_client's outgoing http.client span (the
13181320
# test client is itself sentry-instrumented). In production with separate
13191321
# processes, the server span is the segment; the assertion is the same.
1320-
segments = [item.payload for item in items if item.payload.get("is_segment")]
1321-
assert len(segments) == 1
1322-
assert segments[0]["attributes"]["http.request.body.data"] == json.dumps(body)
1322+
segment = items.pop().payload
1323+
assert segment["is_segment"] is True
1324+
assert segment["attributes"]["http.request.body.data"] == json.dumps(body)
13231325

13241326

13251327
@pytest.mark.asyncio
13261328
async def test_request_body_not_read_span_streaming(
13271329
sentry_init, aiohttp_client, capture_items
13281330
):
1329-
from sentry_sdk.integrations.aiohttp import BODY_NOT_READ_MESSAGE
1330-
13311331
sentry_init(
13321332
integrations=[AioHttpIntegration()],
13331333
traces_sample_rate=1.0,
@@ -1349,9 +1349,9 @@ async def hello(request):
13491349

13501350
sentry_sdk.flush()
13511351

1352-
segments = [item.payload for item in items if item.payload.get("is_segment")]
1353-
assert len(segments) == 1
1354-
assert segments[0]["attributes"]["http.request.body.data"] == BODY_NOT_READ_MESSAGE
1352+
segment = items.pop().payload
1353+
assert segment["is_segment"] is True
1354+
assert segment["attributes"]["http.request.body.data"] == BODY_NOT_READ_MESSAGE
13551355

13561356

13571357
@pytest.mark.asyncio
@@ -1381,12 +1381,9 @@ async def hello(request):
13811381

13821382
sentry_sdk.flush()
13831383

1384-
segments = [item.payload for item in items if item.payload.get("is_segment")]
1385-
assert len(segments) == 1
1386-
assert (
1387-
segments[0]["attributes"]["http.request.body.data"]
1388-
== OVER_SIZE_LIMIT_SUBSTITUTE
1389-
)
1384+
segment = items.pop().payload
1385+
assert segment["is_segment"] is True
1386+
assert segment["attributes"]["http.request.body.data"] == OVER_SIZE_LIMIT_SUBSTITUTE
13901387

13911388

13921389
@pytest.mark.asyncio
@@ -1619,12 +1616,13 @@ async def hello(request):
16191616
assert inner_client_span["attributes"]["http.request.method"] == "GET"
16201617
assert inner_client_span["attributes"]["http.response.status_code"] == 200
16211618
assert inner_client_span["attributes"]["url.query"] == "foo=bar"
1619+
assert inner_client_span["status"] == "ok"
1620+
16221621
url_full = inner_client_span["attributes"]["url.full"]
16231622
# parse_url() splits the URL — url.full is the base URL only, with the
16241623
# query string captured separately on url.query.
16251624
assert url_full.startswith("http://127.0.0.1:")
16261625
assert url_full.endswith("/")
1627-
assert inner_client_span["status"] == "ok"
16281626

16291627

16301628
@pytest.mark.asyncio
@@ -1656,6 +1654,7 @@ async def handler(request):
16561654

16571655
assert client_span["is_segment"] is True
16581656
assert client_span["attributes"]["sentry.op"] == "http.client"
1657+
assert client_span["name"].startswith("GET http://127.0.0.1:")
16591658
assert resp.request_info.headers[
16601659
"sentry-trace"
16611660
] == "{trace_id}-{span_id}-{sampled}".format(

0 commit comments

Comments
 (0)