Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 42 additions & 102 deletions sentry_sdk/integrations/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from sentry_sdk.scope import Scope, should_send_default_pii
from sentry_sdk.sessions import track_session
from sentry_sdk.traces import (
SOURCE_FOR_STYLE,
SegmentNameSource,
Span,
)
Expand All @@ -40,9 +39,7 @@
event_from_exception,
has_data_collection_enabled,
logger,
qualname_from_function,
reraise,
transaction_from_function,
)

if TYPE_CHECKING:
Expand All @@ -57,8 +54,6 @@

_DEFAULT_TRANSACTION_NAME = "generic ASGI request"

TRANSACTION_STYLE_VALUES = ("endpoint", "url")


# Vendored: https://github.com/Kludex/uvicorn/blob/b224045f5900b7f766743bcb16ba9fc3adea2606/uvicorn/_compat.py#L10-L13
if sys.version_info >= (3, 14):
Expand Down Expand Up @@ -95,7 +90,6 @@ class SentryAsgiMiddleware:
__slots__ = (
"app",
"__call__",
"transaction_style",
"mechanism_type",
"span_origin",
"http_methods_to_capture",
Expand All @@ -105,7 +99,6 @@ class SentryAsgiMiddleware:
def __init__(
self,
app: "Any",
transaction_style: str = "endpoint",
mechanism_type: str = "asgi",
span_origin: str = "manual",
http_methods_to_capture: "Tuple[str, ...]" = DEFAULT_HTTP_METHODS_TO_CAPTURE,
Expand All @@ -118,12 +111,6 @@ def __init__(
through the middleware.

"""
if transaction_style not in TRANSACTION_STYLE_VALUES:
raise ValueError(
"Invalid value for transaction_style: %s (must be in %s)"
% (transaction_style, TRANSACTION_STYLE_VALUES)
)

asgi_middleware_while_using_starlette_or_fastapi = (
mechanism_type == "asgi" and "starlette" in _get_installed_modules()
)
Expand All @@ -134,7 +121,6 @@ def __init__(
"See https://docs.sentry.io/platforms/python/guides/asgi/ for more information."
)

self.transaction_style = transaction_style
self.mechanism_type = mechanism_type
self.span_origin = span_origin
self.app = app
Expand Down Expand Up @@ -224,10 +210,7 @@ async def _run_app(
(
transaction_name,
transaction_source,
) = self._get_transaction_name_and_source(
self.transaction_style,
scope,
)
) = self._get_transaction_name_and_source(scope)

method = scope.get("method", "").upper()

Expand Down Expand Up @@ -336,9 +319,7 @@ async def _sentry_wrapped_send(
with capture_internal_exceptions():
if not already_set:
name, source = (
self._get_segment_name_and_source(
self.transaction_style, scope
)
self._get_segment_name_and_source(scope)
)
span.name = name
span.set_attribute(
Expand Down Expand Up @@ -370,9 +351,7 @@ def event_processor(
]
)
if not already_set:
name, source = self._get_transaction_name_and_source(
self.transaction_style, asgi_scope
)
name, source = self._get_transaction_name_and_source(asgi_scope)
event["transaction"] = name
event["transaction_info"] = {"source": source}

Expand All @@ -385,48 +364,28 @@ def event_processor(
# for that.

def _get_transaction_name_and_source(
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Resolved
self: "SentryAsgiMiddleware", transaction_style: str, asgi_scope: "Any"
self: "SentryAsgiMiddleware", asgi_scope: "Any"
) -> "Tuple[str, str]":
name = None
source = SOURCE_FOR_STYLE[transaction_style]
ty = asgi_scope.get("type")

if transaction_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 = transaction_from_function(endpoint) or ""
else:
name = _get_url(
asgi_scope,
"http" if ty == "http" else "ws",
host=None,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.URL

elif transaction_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,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.URL
source = SegmentNameSource.ROUTE

# 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
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
else:
name = _get_url(
asgi_scope,
"http" if asgi_scope.get("type") == "http" else "ws",
host=None,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.URL

if name is None:
name = _DEFAULT_TRANSACTION_NAME
Expand All @@ -436,48 +395,29 @@ def _get_transaction_name_and_source(
return name, source

def _get_segment_name_and_source(
self: "SentryAsgiMiddleware", segment_style: str, asgi_scope: "Any"
self: "SentryAsgiMiddleware", asgi_scope: "Any"
) -> "Tuple[str, str]":
name = None
source = SOURCE_FOR_STYLE[segment_style].value
source = SegmentNameSource.ROUTE.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,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.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,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.URL.value
# 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,
path=_get_path(
asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path
),
)
source = SegmentNameSource.URL.value

if name is None:
name = _DEFAULT_TRANSACTION_NAME
Expand Down
35 changes: 4 additions & 31 deletions sentry_sdk/integrations/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations import DidNotEnable, _check_minimum_version
from sentry_sdk.traces import (
SOURCE_FOR_STYLE,
SegmentNameSource,
Span,
get_current_span,
)
from sentry_sdk.utils import (
has_data_collection_enabled,
parse_version,
transaction_from_function,
)

if TYPE_CHECKING:
from typing import Any, Awaitable, Callable, Dict, Optional
from typing import Any, Awaitable, Callable, Dict

from sentry_sdk._types import Event

Expand Down Expand Up @@ -60,29 +58,6 @@ def setup_once() -> None:
patch_get_request_handler()


def _set_transaction_name_and_source(
scope: "sentry_sdk.Scope",
transaction_style: str,
endpoint: "Optional[Callable[..., Any]]",
route_path: "Optional[str]",
) -> None:
name = ""

if transaction_style == "endpoint" and endpoint:
name = transaction_from_function(endpoint) or ""

elif transaction_style == "url" and route_path is not None:
name = route_path

if not name:
name = _DEFAULT_TRANSACTION_NAME
source = SegmentNameSource.ROUTE
else:
source = SOURCE_FOR_STYLE[transaction_style]

scope.set_transaction_name(name, source=source)


async def _wrap_async_handler(
handler: "Callable[..., Awaitable[Any]]", *args: "Any", **kwargs: "Any"
) -> "Any":
Expand Down Expand Up @@ -122,11 +97,9 @@ async def _wrap_async_handler(
if server_span is not None and route_path is not None:
server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path)

_set_transaction_name_and_source(
sentry_sdk.get_current_scope(),
integration.transaction_style,
endpoint=request.scope.get("endpoint"),
route_path=route_path,
sentry_sdk.get_current_scope().set_transaction_name(
route_path if route_path is not None else _DEFAULT_TRANSACTION_NAME,
source=SegmentNameSource.ROUTE,
)
sentry_scope = sentry_sdk.get_isolation_scope()
extractor = StarletteRequestExtractor(request)
Expand Down
1 change: 0 additions & 1 deletion sentry_sdk/integrations/litestar.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ def __init__(
) -> None:
super().__init__(
app=app,
transaction_style="endpoint",
mechanism_type="asgi",
span_origin=span_origin,
asgi_version=3,
Expand Down
Loading
Loading