feat(asgi): Make integration fully span first compatible#5920
feat(asgi): Make integration fully span first compatible#5920sentrivana wants to merge 25 commits intomasterfrom
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. This PR will not appear in the changelog. 🤖 This preview updates automatically when you update the PR. |
1 similar comment
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. This PR will not appear in the changelog. 🤖 This preview updates automatically when you update the PR. |
Codecov Results 📊✅ 142 passed | Total: 142 | Pass Rate: 100% | Execution Time: 21.70s All tests are passing successfully. ❌ Patch coverage is 7.41%. Project has 14206 uncovered lines. Files with missing lines (4)
Generated by Codecov Action |
| return request_data | ||
|
|
||
|
|
||
| def _get_request_attributes(asgi_scope: "Any") -> "dict[str, Any]": |
There was a problem hiding this comment.
This is an attributes based copy of _get_request_data just above
|
|
||
| return name, source | ||
|
|
||
| def _get_segment_name_and_source( |
There was a problem hiding this comment.
This is a copy of _get_transaction_name_and_source above, just adapted for segments
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Redundant None check after isinstance guard
- Removed the redundant
span is not Nonecondition inside theisinstance(span, StreamedSpan)block to simplify dead logic.
- Removed the redundant
- ✅ Fixed: Duplicate function only differs by enum type used
- Refactored
_get_segment_name_and_sourceto delegate to_get_transaction_name_and_sourceand convert the shared enum result to a string, eliminating duplicated logic.
- Refactored
Or push these changes by commenting:
@cursor push d24d2ecc4c
Preview (d24d2ecc4c)
diff --git a/sentry_sdk/integrations/asgi.py b/sentry_sdk/integrations/asgi.py
--- a/sentry_sdk/integrations/asgi.py
+++ b/sentry_sdk/integrations/asgi.py
@@ -27,7 +27,6 @@
from sentry_sdk.traces import (
StreamedSpan,
SegmentSource,
- SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE,
)
from sentry_sdk.tracing import (
SOURCE_FOR_STYLE,
@@ -45,7 +44,6 @@
_get_installed_modules,
reraise,
capture_internal_exceptions,
- qualname_from_function,
)
from typing import TYPE_CHECKING
@@ -364,8 +362,7 @@
finally:
if isinstance(span, StreamedSpan):
already_set = (
- span is not None
- and span.name != _DEFAULT_TRANSACTION_NAME
+ span.name != _DEFAULT_TRANSACTION_NAME
and span.get_attributes().get("sentry.span.source")
in [
SegmentSource.COMPONENT.value,
@@ -460,36 +457,5 @@
def _get_segment_name_and_source(
self: "SentryAsgiMiddleware", segment_style: str, asgi_scope: "Any"
) -> "Tuple[str, str]":
- name = None
- source = SEGMENT_SOURCE_FOR_STYLE[segment_style].value
- ty = asgi_scope.get("type")
-
- if segment_style == "endpoint":
- endpoint = asgi_scope.get("endpoint")
- # Webframeworks like Starlette mutate the ASGI env once routing is
- # done, which is sometime after the request has started. If we have
- # an endpoint, overwrite our generic transaction name.
- if endpoint:
- name = qualname_from_function(endpoint) or ""
- else:
- name = _get_url(asgi_scope, "http" if ty == "http" else "ws", host=None)
- source = SegmentSource.URL.value
-
- elif segment_style == "url":
- # FastAPI includes the route object in the scope to let Sentry extract the
- # path from it for the transaction name
- route = asgi_scope.get("route")
- if route:
- path = getattr(route, "path", None)
- if path is not None:
- name = path
- else:
- name = _get_url(asgi_scope, "http" if ty == "http" else "ws", host=None)
- source = SegmentSource.URL.value
-
- if name is None:
- name = _DEFAULT_TRANSACTION_NAME
- source = SegmentSource.ROUTE.value
- return name, source
-
- return name, source
+ name, source = self._get_transaction_name_and_source(segment_style, asgi_scope)
+ return name, str(source)This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 77b9298. Configure here.


Description
In span first, there are no event processors. Therefore, we need to be able to set the data we were setting in event processors differently.
As we migrate our integrations one by one, this will be an exercise in whether it's possible to achieve this without some sort of callback/lifecycle hooks. So far, in ASGI, it seems we can get by by simply using
scope.set_attribute()for setting request related data, and updating the segment name/source just before the span ends.Adding this enables us to actually test the new functionality.
To sum up, this PR:
Like in other span first PRs, there is quite a bit of intentional code duplication so that it's easier to remove the legacy implementation in the next major.
Issues
Reminders
tox -e linters.feat:,fix:,ref:,meta:)