Skip to content

fix(spans): Add http.route attribute to HTTP server spans - #7183

Draft
mjq wants to merge 1 commit into
masterfrom
mjq/http-route-server-spans
Draft

fix(spans): Add http.route attribute to HTTP server spans#7183
mjq wants to merge 1 commit into
masterfrom
mjq/http-route-server-spans

Conversation

@mjq

@mjq mjq commented Aug 12, 2026

Copy link
Copy Markdown
Member

Description

Currently the HTTP path template is only available in the span name. Make it available as a semantic attribute as well (http.route - definition in conventions).

This will also let us use this in e.g. HTTP server span description generation, which will be necessary to maintain consistent descriptions between transactions and span streaming.

Issues

@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

PY-2732

Comment thread sentry_sdk/scope.py Outdated
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

112120 passed | ❌ 3 failed | ⏭️ 6763 skipped | Total: 118886 | Pass Rate: 94.31% | Execution Time: 404m 17s

📊 Comparison with Base Branch

Metric Change
Total Tests 📉 -1037
Passed Tests 📉 -1037
Failed Tests 📈 +2
Skipped Tests 📉 -2

➕ New Tests (3)

View new tests
  • test_cache_spans_item_size[True]
    • File: tests.integrations.django.test_cache_module
    • Status: ❌ Failing
  • test_cache_spans_decorator[True]
    • File: tests.integrations.django.test_cache_module
    • Status: ❌ Failing
  • test_aggregates
    • File: tests.test_sessions
    • Status: ❌ Failing

➖ Removed Tests (1)

View removed tests
  • test_span_streaming_quart_auth_user_id[42-True]
    • File: tests.integrations.quart.test_quart

❌ Failed Tests

test_cache_spans_item_size[True]

File: tests.integrations.django.test_cache_module
Suite: py3.10-django-v5.2.17
Error: tests/integrations/django/test_cache_module.py:764: in test_cache_spans_item_size assert not spans[0]["attributes"]["cache.hit"] E assert not True

Stack Trace
tests/integrations/django/test_cache_module.py:764: in test_cache_spans_item_size
    assert not spans[0]["attributes"]["cache.hit"]
E   assert not True

test_cache_spans_decorator[True]

File: tests.integrations.django.test_cache_module
Suite: py3.13-django-v5.2.17
Error: tests/integrations/django/test_cache_module.py:385: in test_cache_spans_decorator assert not spans[0]["attributes"]["cache.hit"] E assert not True

Stack Trace
tests/integrations/django/test_cache_module.py:385: in test_cache_spans_decorator
    assert not spans[0]["attributes"]["cache.hit"]
E   assert not True

test_aggregates

File: tests.test_sessions
Suite: py3.14t-common
Error: AssertionError: assert 2 == 1 + where 2 = len([{'started': '2026-08-13T20:21:00.000000Z', 'errored': 1}, {'started': '2026-08-13T20:22:00.000000Z', 'exited': 2}])

Stack Trace
tests/test_sessions.py:81: in test_aggregates
    assert len(aggregates) == 1
E   AssertionError: assert 2 == 1
E    +  where 2 = len([{'started': '2026-08-13T20:21:00.000000Z', 'errored': 1}, {'started': '2026-08-13T20:22:00.000000Z', 'exited': 2}])

✅ Patch coverage is 95.24%. Project has 2491 uncovered lines.
✅ Project coverage is 90.21%. Comparing base (base) to head (head).

Files with missing lines (1)
File Patch % Lines
sentry_sdk/integrations/asgi.py 80.00% ⚠️ 1 Missing and 1 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    90.21%    90.21%        —%
==========================================
  Files          193       193         —
  Lines        25423     25444       +21
  Branches      9336      9350       +14
==========================================
+ Hits         22933     22953       +20
- Misses        2490      2491        +1
- Partials      1436      1438        +2

Generated by Codecov Action

)
if (
source == SegmentNameSource.ROUTE.value
and name != _DEFAULT_TRANSACTION_NAME

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scope.py sets http.route on default transaction names without matching guard

The ASGI middleware correctly avoids writing http.route for fallback transaction names, but scope.set_transaction_name() in the same PR lacks the same guard. When FastAPI or Starlette hit a 404 and call scope.set_transaction_name(default, ROUTE), http.route is set to a generic string rather than a route template.

Evidence
  • scope.py set_transaction_name unconditionally sets SPANDATA.HTTP_ROUTE whenever source_value == SegmentNameSource.ROUTE.value, without checking name != _DEFAULT_TRANSACTION_NAME.
  • Both FastAPI and Starlette call scope.set_transaction_name(_DEFAULT_TRANSACTION_NAME, TransactionSource.ROUTE) when no route matches the request.
  • For streaming spans, that causes http.route to be set to values like "generic FastAPI request" in attributes, while this hunk explicitly avoids writing the attribute in the same circumstance.

Identified by Warden · code-review · DS5-DYC

@mjq
mjq force-pushed the mjq/http-route-server-spans branch from dddf367 to b1363a5 Compare August 13, 2026 20:16
@mjq

mjq commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@sentry review

@mjq

mjq commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b1363a5. Configure here.

name = _DEFAULT_TRANSACTION_NAME
source = TransactionSource.ROUTE
elif source == TransactionSource.ROUTE:
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starlette sync skips http.route

Medium Severity

set_segment_attribute only writes http.route when the given scope already holds a StreamedSpan. Starlette's sync handler calls _set_transaction_name_and_source with the isolation scope, whose _span is unset, so the attribute is silently dropped for sync endpoints. Async handlers use the current scope and are unaffected.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b1363a5. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http.route missing from HTTP server spans

1 participant