Skip to content

Commit 0aa0591

Browse files
Merge branch 'master' into fix/aiohttp-preserve-sigv4-signed-propagation-headers
2 parents d3cbdd4 + 5e2fcf1 commit 0aa0591

3 files changed

Lines changed: 101 additions & 10 deletions

File tree

‎sentry_sdk/integrations/django/__init__.py‎

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -451,21 +451,19 @@ def _patch_django_asgi_handler() -> None:
451451

452452

453453
def _set_transaction_name_and_source(
454-
scope: "sentry_sdk.Scope", transaction_style: str, request: "WSGIRequest"
454+
scope: "sentry_sdk.Scope",
455+
transaction_style: str,
456+
request: "WSGIRequest",
457+
route_path: "Optional[str]",
455458
) -> None:
456459
try:
457460
transaction_name = None
458461
if transaction_style == "function_name":
459462
fn = resolve(request.path).func
460463
transaction_name = transaction_from_function(getattr(fn, "view_class", fn))
461464

462-
elif transaction_style == "url":
463-
if hasattr(request, "urlconf"):
464-
transaction_name = LEGACY_RESOLVER.resolve(
465-
request.path_info, urlconf=request.urlconf
466-
)
467-
else:
468-
transaction_name = LEGACY_RESOLVER.resolve(request.path_info)
465+
elif transaction_style == "url" and route_path is not None:
466+
transaction_name = route_path
469467

470468
if transaction_name is None:
471469
transaction_name = request.path_info
@@ -477,6 +475,11 @@ def _set_transaction_name_and_source(
477475
transaction_name,
478476
source=source,
479477
)
478+
479+
if transaction_style == "url" and route_path is not None:
480+
server_span = scope._server_segment_span
481+
if server_span is not None:
482+
server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path)
480483
except Resolver404:
481484
urlconf = import_module(settings.ROOT_URLCONF)
482485
# This exception only gets thrown when transaction_style is `function_name`
@@ -501,8 +504,29 @@ def _before_get_response(request: "WSGIRequest") -> None:
501504
_patch_drf()
502505

503506
scope = sentry_sdk.get_current_scope()
507+
508+
route_path = None
509+
if hasattr(request, "urlconf"):
510+
try:
511+
route_path = LEGACY_RESOLVER.resolve(
512+
request.path_info, urlconf=request.urlconf
513+
)
514+
except Exception:
515+
pass
516+
else:
517+
try:
518+
route_path = LEGACY_RESOLVER.resolve(request.path_info)
519+
except Exception:
520+
pass
521+
522+
server_span = sentry_sdk.get_current_scope()._server_segment_span
523+
if server_span is not None and route_path is not None:
524+
server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path)
525+
504526
# Rely on WSGI middleware to start a trace
505-
_set_transaction_name_and_source(scope, integration.transaction_style, request)
527+
_set_transaction_name_and_source(
528+
scope, integration.transaction_style, request, route_path=route_path
529+
)
506530

507531
scope.add_event_processor(
508532
_make_wsgi_request_event_processor(weakref.ref(request), integration)
@@ -520,7 +544,27 @@ def _attempt_resolve_again(
520544
if not hasattr(request, "urlconf"):
521545
return
522546

523-
_set_transaction_name_and_source(scope, transaction_style, request)
547+
route_path = None
548+
if hasattr(request, "urlconf"):
549+
try:
550+
route_path = LEGACY_RESOLVER.resolve(
551+
request.path_info, urlconf=request.urlconf
552+
)
553+
except Exception:
554+
pass
555+
else:
556+
try:
557+
route_path = LEGACY_RESOLVER.resolve(request.path_info)
558+
except Exception:
559+
pass
560+
561+
server_span = sentry_sdk.get_current_scope()._server_segment_span
562+
if server_span is not None and route_path is not None:
563+
server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path)
564+
565+
_set_transaction_name_and_source(
566+
scope, transaction_style, request, route_path=route_path
567+
)
524568

525569

526570
def _get_user_from_request_and_set_on_scope(request: "WSGIRequest") -> None:

‎tests/integrations/django/asgi/test_asgi.py‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,33 @@ async def test_async_views(
197197
}
198198

199199

200+
@pytest.mark.parametrize("application", APPS)
201+
@pytest.mark.asyncio
202+
@pytest.mark.skipif(
203+
django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1"
204+
)
205+
async def test_http_route(
206+
sentry_init,
207+
capture_items,
208+
application,
209+
):
210+
sentry_init(
211+
integrations=[DjangoIntegration()],
212+
traces_sample_rate=1.0,
213+
trace_lifecycle="stream",
214+
)
215+
216+
items = capture_items("span")
217+
218+
comm = HttpCommunicator(application, "GET", "/async_message")
219+
await comm.get_response()
220+
await comm.wait()
221+
222+
sentry_sdk.flush()
223+
(segment,) = (item.payload for item in items if item.payload.get("is_segment"))
224+
assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/async_message"
225+
226+
200227
@pytest.mark.parametrize("application", APPS)
201228
@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"])
202229
@pytest.mark.parametrize("middleware_spans", [False, True])

‎tests/integrations/django/test_basic.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,26 @@ def test_transaction_style_tracing_disabled(
11481148
assert event["transaction"] == expected_transaction
11491149

11501150

1151+
def test_http_route(
1152+
sentry_init,
1153+
client,
1154+
capture_items,
1155+
):
1156+
sentry_init(
1157+
integrations=[DjangoIntegration()],
1158+
traces_sample_rate=1.0,
1159+
trace_lifecycle="stream",
1160+
)
1161+
1162+
items = capture_items("span")
1163+
1164+
unpack_werkzeug_response(client.get("/message"))
1165+
1166+
sentry_sdk.flush()
1167+
(segment,) = (item.payload for item in items if item.payload.get("is_segment"))
1168+
assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/message"
1169+
1170+
11511171
@pytest.mark.parametrize("span_streaming", [True, False])
11521172
def test_request_body(
11531173
sentry_init,

0 commit comments

Comments
 (0)