feat(stdlib): Support span streaming #6154
3 issues
find-bugs: Found 3 issues (1 high, 1 medium, 1 low)
High
request_span.span_id raises AttributeError on serialized span dict - `tests/integrations/stdlib/test_httplib.py:245`
After switching from transaction._span_recorder.spans[-1] (a Span object) to event["spans"][-1] (a serialized dict in the captured event), the code still uses attribute access request_span.span_id. Captured event spans are dictionaries and must be accessed with request_span["span_id"] (as is done elsewhere in the test suite, e.g. tests/integrations/asyncio/test_asyncio.py and tests/integrations/celery/test_celery.py). The test will fail with AttributeError before reaching the assertion.
Also found at:
tests/integrations/stdlib/test_httplib.py:289
Medium
span_streaming branch in subprocess instrumentation is identical to non-streaming branch, making feature a no-op - `sentry_sdk/integrations/stdlib.py:260-271`
Both arms of if span_streaming: call sentry_sdk.start_span(op=..., name=..., origin=...) with identical arguments. Compare to the httplib instrumentation in the same file (lines 108-126), where the streaming branch invokes sentry_sdk.traces.start_span(name=..., attributes={'sentry.origin': ..., 'sentry.op': ...}) to obtain a StreamedSpan. As written, the type annotation Union[Span, StreamedSpan] is misleading because span will never actually be a StreamedSpan, and span streaming silently does nothing for subprocess spans. Downstream isinstance(span, StreamedSpan) checks (used elsewhere in this file) will never trigger here, so subprocess spans will not be emitted via the streaming pipeline when the feature is enabled.
Low
Leftover debug `print("span is here")` statement in getresponse - `sentry_sdk/integrations/stdlib.py:162`
A debug print("span is here") was left in the patched getresponse function. This will write to stdout on every HTTP response handled by an instrumented HTTPConnection, which constitutes information disclosure into application logs/stdout and adds unbounded noisy output in production. While not a direct security vulnerability, it can leak request flow information and pollute logs at scale.
Duration: 1m 15s · Tokens: 278.3k in / 5.7k out · Cost: $1.20 (+merge: $0.00)
Annotations
Check failure on line 245 in tests/integrations/stdlib/test_httplib.py
sentry-warden / warden: find-bugs
request_span.span_id raises AttributeError on serialized span dict
After switching from `transaction._span_recorder.spans[-1]` (a Span object) to `event["spans"][-1]` (a serialized dict in the captured event), the code still uses attribute access `request_span.span_id`. Captured event spans are dictionaries and must be accessed with `request_span["span_id"]` (as is done elsewhere in the test suite, e.g. tests/integrations/asyncio/test_asyncio.py and tests/integrations/celery/test_celery.py). The test will fail with AttributeError before reaching the assertion.
Check failure on line 289 in tests/integrations/stdlib/test_httplib.py
sentry-warden / warden: find-bugs
[MUA-25M] request_span.span_id raises AttributeError on serialized span dict (additional location)
After switching from `transaction._span_recorder.spans[-1]` (a Span object) to `event["spans"][-1]` (a serialized dict in the captured event), the code still uses attribute access `request_span.span_id`. Captured event spans are dictionaries and must be accessed with `request_span["span_id"]` (as is done elsewhere in the test suite, e.g. tests/integrations/asyncio/test_asyncio.py and tests/integrations/celery/test_celery.py). The test will fail with AttributeError before reaching the assertion.
Check warning on line 271 in sentry_sdk/integrations/stdlib.py
sentry-warden / warden: find-bugs
span_streaming branch in subprocess instrumentation is identical to non-streaming branch, making feature a no-op
Both arms of `if span_streaming:` call `sentry_sdk.start_span(op=..., name=..., origin=...)` with identical arguments. Compare to the httplib instrumentation in the same file (lines 108-126), where the streaming branch invokes `sentry_sdk.traces.start_span(name=..., attributes={'sentry.origin': ..., 'sentry.op': ...})` to obtain a `StreamedSpan`. As written, the type annotation `Union[Span, StreamedSpan]` is misleading because `span` will never actually be a `StreamedSpan`, and span streaming silently does nothing for subprocess spans. Downstream `isinstance(span, StreamedSpan)` checks (used elsewhere in this file) will never trigger here, so subprocess spans will not be emitted via the streaming pipeline when the feature is enabled.