feat: Add enrichers for attribute-based telemetry #5725
6 issues
High
Missing parentheses on get_attributes() method call causes AttributeError at runtime - `sentry_sdk/integrations/asgi.py:220`
The enricher method being added has a bug at line 394 where segment.get_attributes.get("sentry.span.source") is missing parentheses. get_attributes is a method (as seen in sentry_sdk/traces.py:403), not a property, so this should be segment.get_attributes().get(...). When the enricher registered at line 220 executes, it will fail because calling .get() on a bound method object will raise an AttributeError, breaking span enrichment for ASGI requests.
Also found at:
sentry_sdk/integrations/asgi.py:394sentry_sdk/integrations/asgi.py:393-396
Missing parentheses causes AttributeError: get_attributes is a method, not a property - `sentry_sdk/integrations/asgi.py:394`
Line 394 uses segment.get_attributes.get("sentry.span.source") but get_attributes is a method on StreamedSpan (defined in traces.py line 403) that must be called with parentheses to return the attributes dictionary. Without parentheses, .get() is being called on the method object itself, which will raise AttributeError: 'method' object has no attribute 'get'. This will cause the enricher to fail at runtime when processing spans.
Null check for segment occurs after segment is accessed, causing potential AttributeError - `sentry_sdk/integrations/asgi.py:393-404`
Line 394 accesses segment.get_attributes before the null check on line 395-397 (segment is not None). If telemetry.segment were ever None, line 394 would raise AttributeError: 'NoneType' object has no attribute 'get_attributes' before the null check executes. The check should happen before accessing segment's attributes. While current StreamedSpan implementation always sets _segment to a non-None value, this is a defensive programming issue that could cause crashes if the implementation changes.
Medium
Null values assigned to attributes may cause downstream issues - `sentry_sdk/integrations/_asgi_common.py:119-126`
Both asgi_scope.get('method') (line 119) and _get_query(asgi_scope) (line 126) can return None, but the Attributes type (defined in _types.py) does not include None as a valid AttributeValue. While the return type annotation is Dict[str, Any], the internal annotation uses Attributes, and downstream consumers expecting valid attribute values may encounter unexpected None values that don't conform to OpenTelemetry attribute semantics.
Low
Test enricher function doesn't return telemetry as required by type signature - `tests/tracing/test_span_streaming.py:1516-1517`
The enricher function in test_enrichers modifies telemetry in-place but doesn't return it. While this works because the object is mutated, the Enricher type signature in _types.py is Callable[[Telemetry], Telemetry] which expects a return value. The stdlib integration's enricher correctly returns telemetry. This inconsistency could mislead developers implementing enrichers.
_run_enrichers returns None but type annotation doesn't include Optional - `sentry_sdk/scope.py:1874`
The _run_enrichers method has return type annotation Union[Log, Metric, StreamedSpan] but implicitly returns None (bare return on line 1874) when telemetry is not a StreamedSpan. This type mismatch means static type checkers will not catch potential bugs where callers expect a non-None return value.
4 skills analyzed
| Skill | Findings | Duration | Cost |
|---|---|---|---|
| code-review | 3 | 9m 16s | $3.73 |
| find-bugs | 3 | 4m 18s | $7.39 |
| skill-scanner | 0 | 8m 25s | $0.96 |
| security-review | 0 | 5m 34s | $1.89 |
Duration: 27m 33s · Tokens: 8.9M in / 81.3k out · Cost: $14.00 (+extraction: $0.01, +merge: $0.00, +fix_gate: $0.01, +dedup: $0.00)