8000 Unpack custom_sampling_context into attributes in ASGI (#3764) · getsentry/sentry-python@13ec94f · GitHub
[go: up one dir, main page]

Skip to content

Commit 13ec94f

Browse files
authored
Unpack custom_sampling_context into attributes in ASGI (#3764)
1 parent ff7e134 commit 13ec94f

File tree

5 files changed

+34
-2
lines changed

5 files changed

+34
-2
lines changed

MIGRATION_GUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
2020
- clickhouse-driver integration: The query is now available under the `db.query.text` span attribute (only if `send_default_pii` is `True`).
2121
- `sentry_sdk.init` now returns `None` instead of a context manager.
2222
- The `sampling_context` argument of `traces_sampler` now additionally contains all span attributes known at span start.
23+
- The `sampling_context` argument of `traces_sampler` doesn't contain the `asgi_scope` object anymore for ASGI frameworks. Instead, the individual properties, if available, are accessible as `asgi_scope.endpoint`, `asgi_scope.path`, `asgi_scope.root_path`, `asgi_scope.route`, `asgi_scope.scheme`, `asgi_scope.server` and `asgi_scope.type`.
2324

2425
### Removed
2526

sentry_sdk/integrations/asgi.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ async def _run_app(self, scope, receive, send, asgi_version):
209209
name=transaction_name,
210210
source=transaction_source,
211211
origin=self.span_origin,
212-
custom_sampling_context={"asgi_scope": scope},
212+
attributes=_prepopulate_attributes(scope),
213213
)
214214
if should_trace
215215
else nullcontext()
@@ -324,3 +324,16 @@ def _get_transaction_name_and_source(self, transaction_style, asgi_scope):
324324
return name, source
325325

326326
return name, source
327+
328+
329+
def _prepopulate_attributes(scope):
330+
# type: (Any) -> dict[str, Any]
331+
"""Unpack asgi_scope into serializable attributes."""
332+
scope = scope or {}
333+
334+
attributes = {}
335+
for attr in ("endpoint", "path", "root_path", "route", "scheme", "server", "type"):
336+
if scope.get(attr):
337+
attributes[f"asgi_scope.{attr}"] = scope[attr]
338+
339+
return attributes

sentry_sdk/integrations/opentelemetry/sampler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ def should_sample(
147147
"transaction_context": {
148148
"name": name,
149149
"op": attributes.get(SentrySpanAttribute.OP),
150+
"source": attributes.get(SentrySpanAttribute.SOURCE),
150151
},
151152
"parent_sampled": get_parent_sampled(parent_span_context, trace_id),
152153
}

sentry_sdk/tracing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,7 @@ def __init__(
12501250
# Prepopulate some attrs so that they're accessible in traces_sampler
12511251
attributes = attributes or {}
12521252
attributes[SentrySpanAttribute.OP] = op
1253+
attributes[SentrySpanAttribute.SOURCE] = source
12531254
if sampled is not None:
12541255
attributes[SentrySpanAttribute.CUSTOM_SAMPLED] = sampled
12551256

@@ -1260,7 +1261,6 @@ def __init__(
12601261
self.origin = origin or DEFAULT_SPAN_ORIGIN
12611262
self.description = description
12621263
self.name = span_name
1263-
self.source = source
12641264

12651265
if status is not None:
12661266
self.set_status(status)

tests/integrations/asgi/test_asgi.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,20 @@ async def test_custom_transaction_name(
721721
assert transaction_event["type"] == "transaction"
722722
assert transaction_event["transaction"] == "foobar"
723723
assert transaction_event["transaction_info"] == {"source": "custom"}
724+
725+
726+
@pytest.mark.asyncio
727+
async def test_asgi_scope_in_traces_sampler(sentry_init, asgi3_app):
728+
def dummy_traces_sampler(sampling_context):
729+
assert sampling_context["asgi_scope.path"] == "/test"
730+
assert sampling_context["asgi_scope.scheme"] == "http"
731+
732+
sentry_init(
733+
traces_sampler=dummy_traces_sampler,
734+
traces_sample_rate=1.0,
735+
)
736+
737+
app = SentryAsgiMiddleware(asgi3_app)
738+
739+
async with TestClient(app) as client:
740+
await client.get("/test")

0 commit comments

Comments
 (0)
0