Skip to content

Commit 20d2496

Browse files
committed
feat(integrations): Add http.route attribute to server spans
1 parent 14ddfb8 commit 20d2496

23 files changed

Lines changed: 201 additions & 22 deletions

File tree

‎sentry_sdk/consts.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,12 @@ class SPANDATA:
878878
Example: GET
879879
"""
880880

881+
HTTP_ROUTE = "http.route"
882+
"""
883+
The matched route, that is, the path template used to match the request.
884+
Example: /users/{id}
885+
"""
886+
881887
HTTP_QUERY = "http.query"
882888
"""
883889
The Query string present in the URL.

‎sentry_sdk/integrations/aiohttp.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
SegmentNameSource,
2727
SpanStatus,
2828
StreamedSpan,
29+
get_current_span,
2930
)
3031
from sentry_sdk.tracing import (
3132
BAGGAGE_HEADER_NAME,
@@ -324,14 +325,15 @@ async def sentry_urldispatcher_resolve(
324325
return rv
325326

326327
name = None
328+
http_route = None
327329

328330
try:
329331
if integration.transaction_style == "handler_name":
330332
name = transaction_from_function(rv.handler)
331333
elif integration.transaction_style == "method_and_path_pattern":
332334
route_info = rv.get_info()
333-
pattern = route_info.get("path") or route_info.get("formatter")
334-
name = "{} {}".format(request.method, pattern)
335+
http_route = route_info.get("path") or route_info.get("formatter")
336+
name = "{} {}".format(request.method, http_route)
335337
except Exception:
336338
pass
337339

@@ -341,6 +343,13 @@ async def sentry_urldispatcher_resolve(
341343
name,
342344
source=SOURCE_FOR_STYLE[integration.transaction_style],
343345
)
346+
current_span = get_current_span()
347+
if (
348+
current_span
349+
and not isinstance(current_span, NoOpStreamedSpan)
350+
and http_route is not None
351+
):
352+
current_span._segment.set_attribute(SPANDATA.HTTP_ROUTE, http_route)
344353

345354
return rv
346355

‎sentry_sdk/integrations/asgi.py‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,19 @@ async def _run_app(
246246
span_ctx: "ContextManager[Union[Span, StreamedSpan, None]]"
247247
if span_streaming:
248248
segment: "Optional[StreamedSpan]" = None
249+
segment_source = getattr(
250+
transaction_source, "value", transaction_source
251+
)
249252
attributes: "Attributes" = {
250-
"sentry.segment.name.source": getattr(
251-
transaction_source, "value", transaction_source
252-
),
253+
"sentry.segment.name.source": segment_source,
253254
"sentry.origin": self.span_origin,
254255
"network.protocol.name": ty,
255256
}
257+
if (
258+
segment_source == SegmentNameSource.ROUTE.value
259+
and transaction_name != _DEFAULT_TRANSACTION_NAME
260+
):
261+
attributes[SPANDATA.HTTP_ROUTE] = transaction_name
256262

257263
if scope.get("client"):
258264
client_options = sentry_sdk.get_client().options
@@ -412,6 +418,13 @@ async def _sentry_wrapped_send(
412418
span.set_attribute(
413419
"sentry.segment.name.source", source
414420
)
421+
if (
422+
source == SegmentNameSource.ROUTE.value
423+
and name != _DEFAULT_TRANSACTION_NAME
424+
):
425+
span.set_attribute(
426+
SPANDATA.HTTP_ROUTE, name
427+
)
415428
finally:
416429
_asgi_middleware_applied.set(False)
417430

‎sentry_sdk/integrations/bottle.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import TYPE_CHECKING
33

44
import sentry_sdk
5+
from sentry_sdk.consts import SPANDATA
56
from sentry_sdk.integrations import (
67
_DEFAULT_FAILED_REQUEST_STATUS_CODES,
78
DidNotEnable,
@@ -10,8 +11,15 @@
1011
)
1112
from sentry_sdk.integrations._wsgi_common import RequestExtractor
1213
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
13-
from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE
14-
from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE
14+
from sentry_sdk.traces import (
15+
SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE,
16+
)
17+
from sentry_sdk.traces import (
18+
SegmentNameSource,
19+
)
20+
from sentry_sdk.tracing import (
21+
SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE,
22+
)
1523
from sentry_sdk.tracing_utils import has_span_streaming_enabled
1624
from sentry_sdk.utils import (
1725
capture_internal_exceptions,
@@ -181,9 +189,15 @@ def _set_segment_name_and_source(transaction_style: str) -> None:
181189
or "bottle request"
182190
)
183191

192+
source = SEGMENT_SOURCE_FOR_STYLE[transaction_style]
193+
if source == SegmentNameSource.ROUTE:
194+
sentry_sdk.get_current_scope().set_segment_attribute(
195+
SPANDATA.HTTP_ROUTE, name
196+
)
197+
184198
sentry_sdk.get_current_scope().set_transaction_name(
185199
name,
186-
source=SEGMENT_SOURCE_FOR_STYLE[transaction_style],
200+
source=source,
187201
)
188202
except RuntimeError:
189203
pass

‎sentry_sdk/integrations/django/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,8 @@ def _set_transaction_name_and_source(
472472
source = TransactionSource.URL
473473
else:
474474
source = SOURCE_FOR_STYLE[transaction_style]
475+
if source == TransactionSource.ROUTE:
476+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, transaction_name)
475477

476478
scope.set_transaction_name(
477479
transaction_name,

‎sentry_sdk/integrations/falcon.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from typing import TYPE_CHECKING
22

33
import sentry_sdk
4+
from sentry_sdk.consts import SPANDATA
45
from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version
56
from sentry_sdk.integrations._wsgi_common import RequestExtractor
67
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
8+
from sentry_sdk.traces import SegmentNameSource
79
from sentry_sdk.tracing import SOURCE_FOR_STYLE
810
from sentry_sdk.tracing_utils import has_span_streaming_enabled
911
from sentry_sdk.utils import (
@@ -122,7 +124,10 @@ def process_resource(
122124
}
123125
name = name_for_style[integration.transaction_style]
124126
source = sentry_sdk.traces.SOURCE_FOR_STYLE[integration.transaction_style]
125-
sentry_sdk.set_transaction_name(name, source)
127+
scope = sentry_sdk.get_current_scope()
128+
if source == SegmentNameSource.ROUTE:
129+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)
130+
scope.set_transaction_name(name, source)
126131

127132

128133
TRANSACTION_STYLE_VALUES = ("uri_template", "path")

‎sentry_sdk/integrations/fastapi.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ def _set_transaction_name_and_source(
8484
source = TransactionSource.ROUTE
8585
else:
8686
source = SOURCE_FOR_STYLE[transaction_style]
87+
if source == TransactionSource.ROUTE:
88+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)
8789

8890
scope.set_transaction_name(name, source=source)
8991

‎sentry_sdk/integrations/flask.py‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from typing import TYPE_CHECKING
22

33
import sentry_sdk
4+
from sentry_sdk.consts import SPANDATA
45
from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version
56
from sentry_sdk.integrations._wsgi_common import (
67
DEFAULT_HTTP_METHODS_TO_CAPTURE,
78
RequestExtractor,
89
)
910
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
1011
from sentry_sdk.scope import should_send_default_pii
11-
from sentry_sdk.tracing import SOURCE_FOR_STYLE
12+
from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource
1213
from sentry_sdk.utils import (
1314
capture_internal_exceptions,
1415
ensure_integration_enabled,
@@ -134,10 +135,11 @@ def _set_transaction_name_and_source(
134135
"url": request.url_rule.rule,
135136
"endpoint": request.url_rule.endpoint,
136137
}
137-
scope.set_transaction_name(
138-
name_for_style[transaction_style],
139-
source=SOURCE_FOR_STYLE[transaction_style],
140-
)
138+
name = name_for_style[transaction_style]
139+
source = SOURCE_FOR_STYLE[transaction_style]
140+
if source == TransactionSource.ROUTE:
141+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)
142+
scope.set_transaction_name(name, source=source)
141143
except Exception:
142144
pass
143145

‎sentry_sdk/integrations/pyramid.py‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
import weakref
55

66
import sentry_sdk
7+
from sentry_sdk.consts import SPANDATA
78
from sentry_sdk.integrations import DidNotEnable, Integration
89
from sentry_sdk.integrations._wsgi_common import RequestExtractor
910
from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware
1011
from sentry_sdk.scope import should_send_default_pii
11-
from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE
12+
from sentry_sdk.traces import (
13+
SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE,
14+
)
15+
from sentry_sdk.traces import (
16+
SegmentNameSource,
17+
)
1218
from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE
1319
from sentry_sdk.tracing_utils import has_span_streaming_enabled
1420
from sentry_sdk.utils import (
@@ -182,8 +188,12 @@ def _set_transaction_name_and_source(
182188
if is_span_streaming_enabled
183189
else TRANSACTION_SOURCE_FOR_STYLE[transaction_style]
184190
)
191+
name = name_for_style[transaction_style]
192+
if source == SegmentNameSource.ROUTE:
193+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)
194+
185195
scope.set_transaction_name(
186-
name_for_style[transaction_style],
196+
name,
187197
source=source,
188198
)
189199
except Exception:

‎sentry_sdk/integrations/quart.py‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@
55
from typing import TYPE_CHECKING
66

77
import sentry_sdk
8+
from sentry_sdk.consts import SPANDATA
89
from sentry_sdk.data_collection import _apply_data_collection_filtering_to_query_string
910
from sentry_sdk.integrations import DidNotEnable, Integration
1011
from sentry_sdk.integrations._wsgi_common import _filter_headers
1112
from sentry_sdk.integrations.asgi import SentryAsgiMiddleware
1213
from sentry_sdk.scope import should_send_default_pii
1314
from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE
14-
from sentry_sdk.traces import StreamedSpan, get_current_span
15-
from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE
15+
from sentry_sdk.traces import SegmentNameSource, StreamedSpan, get_current_span
16+
from sentry_sdk.tracing import (
17+
SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE,
18+
)
19+
from sentry_sdk.tracing import (
20+
TransactionSource,
21+
)
1622
from sentry_sdk.tracing_utils import has_span_streaming_enabled
1723
from sentry_sdk.utils import (
1824
capture_internal_exceptions,
@@ -163,8 +169,12 @@ def _set_transaction_name_and_source(
163169
else TRANSACTION_SOURCE_FOR_STYLE[transaction_style]
164170
)
165171

172+
name = name_for_style[transaction_style]
173+
if source in (TransactionSource.ROUTE, SegmentNameSource.ROUTE):
174+
scope.set_segment_attribute(SPANDATA.HTTP_ROUTE, name)
175+
166176
scope.set_transaction_name(
167-
name=name_for_style[transaction_style],
177+
name=name,
168178
source=source,
169179
)
170180
except Exception:

0 commit comments

Comments
 (0)