Skip to content

feat(span-first): Support before_send_span#6239

Draft
sentrivana wants to merge 16 commits into
masterfrom
ivana/span-first-before-send-span
Draft

feat(span-first): Support before_send_span#6239
sentrivana wants to merge 16 commits into
masterfrom
ivana/span-first-before-send-span

Conversation

@sentrivana
Copy link
Copy Markdown
Contributor

@sentrivana sentrivana commented May 8, 2026

Description

Add support for before_send_span in span streaming mode.

before_send_span is different from before_send_metric and before_send_log in that:

  • it doesn't allow users to drop a span (i.e., return None)
  • it only allows to modify specific parts of the span

To that end, we're now serializing the span earlier, and exposing the serialized dictionary in the before_send callback. This is consistent with metrics and logs. It also means we're now queuing dictionaries instead of StreamedSpan instances in the span batcher, which should also decrease our memory footprint.

See https://develop.sentry.dev/sdk/telemetry/spans/scrubbing-data/ for spec.

Issues

@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 8, 2026

PY-2057

@sentrivana sentrivana changed the title feat(span-first): Support before_send_span feat(span-first): Support before_send_span May 8, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Codecov Results 📊

67 passed | Total: 67 | Pass Rate: 100% | Execution Time: 9.51s

📊 Comparison with Base Branch

Metric Change
Total Tests
Passed Tests
Failed Tests
Skipped Tests

✨ No test changes detected

All tests are passing successfully.

❌ Patch coverage is 63.04%. Project has 14264 uncovered lines.
✅ Project coverage is 35.35%. Comparing base (base) to head (head).

Files with missing lines (6)
File Patch % Lines
utils.py 56.82% ⚠️ 405 Missing and 85 partials
client.py 63.36% ⚠️ 203 Missing and 70 partials
traces.py 67.29% ⚠️ 105 Missing and 20 partials
_span_batcher.py 81.67% ⚠️ 22 Missing and 10 partials
_types.py 73.81% ⚠️ 11 Missing
consts.py 99.48% ⚠️ 2 Missing
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    35.16%    35.35%    +0.19%
==========================================
  Files          190       190         —
  Lines        22039     22064       +25
  Branches      7408      7420       +12
==========================================
+ Hits          7748      7800       +52
- Misses       14291     14264       -27
- Partials       717       717         —

Generated by Codecov Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 8, 2026

Codecov Results 📊

44 passed | ❌ 13 failed | Total: 57 | Pass Rate: 77.19% | Execution Time: 9.62s

❌ Failed Tests

test_tracing_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:42227/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1159: in test_tracing_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:42227/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_sensitive_header_scrubbing_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:43849/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1227: in test_sensitive_header_scrubbing_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:43849/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_sensitive_header_passthrough_with_pii_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: ValueError: not enough values to unpack (expected 1, got 0)

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1273: in test_sensitive_header_passthrough_with_pii_span_streaming
    (server_span,) = [item.payload for item in items]
E   ValueError: not enough values to unpack (expected 1, got 0)

test_request_body_captured_on_segment_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:37321/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1311: in test_request_body_captured_on_segment_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:37321/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_request_body_not_read_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:45665/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1341: in test_request_body_not_read_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:45665/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:13 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_request_body_over_size_limit_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:44169/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1375: in test_request_body_over_size_limit_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:44169/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_url_query_attribute_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:44099/?foo=bar&baz=qux) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1407: in test_url_query_attribute_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:44099/?foo=bar&baz=qux) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_transaction_style_span_streaming[pyloop-/message-handler_name-tests.integrations.aiohttp.test_aiohttp.test_transaction_style_span_streaming.<locals>.hello-component]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:42867/message) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1461: in test_transaction_style_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:42867/message) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_transaction_style_span_streaming[pyloop-/message-method_and_path_pattern-GET /{var}-route]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 200 + where 500 = <ClientResponse(http://127.0.0.1:36003/message) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1461: in test_transaction_style_span_streaming
    assert resp.status == 200
E   AssertionError: assert 500 == 200
E    +  where 500 = <ClientResponse(http://127.0.0.1:36003/message) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:14 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_server_error_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: assert 2 == 3 + where 2 = len([UnwrappedItem(type='event', payload={'level': 'error', 'exception': {'values': [{'mechanism': {'type': 'aiohttp', 'handled': False}, 'module': None, 'type': 'ZeroDivisionError', 'value': 'division by zero', 'stacktrace': {'frames': [{'filename': 'aiohttp/web_app.py', 'abs_path': '/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/aiohttp/web_app.py', 'function': '_handle', 'module': 'aiohttp.web_app', 'lineno': 499, 'pre_context': [' partial(m, handler=handler), handler', ' )', ' else:', ' handler = await m(app, handler) # type: ignore', ''], 'context_line': ' resp = await handler(request)', 'post_context': ['', ' return resp', '', ' def call(self) -> "Application":', ' """gunicorn compatibility"""'], 'vars': {'self': {}, 'request': {}, 'loop': '<_UnixSelectorEventLoop running=True closed=False debug=False>', 'debug': 'False', 'match_info': {}, 'resp': 'None', 'expect': 'None', 'handler': '<function test_server_error_span_streaming..hello at 0x7f1991790430>'}, 'in_app': False}, {'filename': 'tests/integrations/aiohttp/test_aiohttp.py', 'abs_path': '/home/runner/work/sentry-python/sentry-python/tests/integrations/aiohttp/test_aiohttp.py', 'function': 'hello', 'module': 'tests.integrations.aiohttp.test_aiohttp', 'lineno': 1482, 'pre_context': [' traces_sample_rate=1.0,', ' _experiments={"trace_lifecycle": "stream"},', ' )', '', ' async def hello(request):'], 'context_line': ' 1 / 0', 'post_context': ['', ' app = web.Application()', ' app.router.add_get("/", hello)', '', ' items = capture_items("event", "span")'], 'vars': {'request': {}}, 'in_app': True}]}}]}, 'event_id': '595dd3acd8fb47ceb8b815b13297740f', 'timestamp': '2026-05-08T13:12:14.841597Z', 'contexts': {'trace': {'trace_id': '357daa0339ac4d38a585a0b806ac6cb2', 'span_id': 'b1e93bf9c589f2e8', 'parent_span_id': 'ab82f4ee25431eae', 'op': 'http.server', 'origin': 'auto.http.aiohttp'}, 'runtime': {'name': 'CPython', 'version': '3.9.25', 'build': '3.9.25 (main, Nov 3 2025, 15:14:54) \n[GCC 11.4.0]'}}, 'transaction': 'tests.integrations.aiohttp.test_aiohttp.test_server_error_span_streaming..hello', 'transaction_info': {'source': <TransactionSource.COMPONENT: 'component'>}, 'breadcrumbs': {'values': []}, 'extra': {'sys.argv': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/main.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4']}, 'modules': {'sentry-sdk': '2.59.0', 'pytest-aiohttp': '0.3.0', 'multidict': '6.7.1', 'iniconfig': '2.1.0', 'pytest-forked': '1.6.0', 'charset-normalizer': '3.4.7', 'jsonschema': '4.25.1', 'wheel': '0.43.0', 'propcache': '0.4.1', 'tomli': '2.4.1', 'pyyaml': '6.0.3', 'coverage': '7.10.7', 'pytest-localserver': '0.10.0', 'certifi': '2026.4.22', 'hyperframe': '6.1.0', 'colorama': '0.4.6', 'pygments': '2.20.0', 'markupsafe': '3.0.3', 'referencing': '0.36.2', 'pysocks': '1.7.1', 'setuptools': '69.5.1', 'httpcore': '1.0.9', 'urllib3': '2.6.3', 'yarl': '1.22.0', 'h2': '4.3.0', 'hpack': '4.1.0', 'pytest-timeout': '2.4.0', 'asttokens': '3.0.1', 'idna': '3.13', 'py': '1.11.0', 'async-timeout': '3.0.1', 'pytest-watch': '4.2.0', 'pluggy': '1.6.0', 'aiohttp': '3.7.4', 'watchdog': '6.0.0', 'brotli': '1.2.0', 'pytest-cov': '7.1.0', 'responses': '0.26.0', 'socksio': '1.0.0', 'pip': '24.0', 'requests': '2.32.5', 'docopt': '0.6.2', 'typing_extensions': '4.15.0', 'docker': '7.1.0', 'executing': '2.2.1', 'werkzeug': '3.1.8', 'jsonschema-specifications': '2025.9.1', 'h11': '0.16.0', 'packaging': '26.2', 'chardet': '3.0.4', 'attrs': '26.1.0', 'rpds-py': '0.27.1', 'pytest': '8.4.2', 'exceptiongroup': '1.3.1'}, 'request': {'url': 'http://127.0.0.1:41929/', 'query_string': '', 'method': 'GET', 'env': {'REMOTE_ADDR': '127.0.0.1'}, 'headers': {'Host': '127.0.0.1:41929', 'sentry-trace': '357daa0339ac4d38a585a0b806ac6cb2-ab82f4ee25431eae-1', 'baggage': 'sentry-trace_id=357daa0339ac4d38a585a0b806ac6cb2,sentry-sample_rand=0.034682,sentry-environment=production,sentry-release=fe5b14821f6fcc5acfdab3744c00cc8d3876e65f,sentry-transaction=GET%20http%3A//127.0.0.1%3A41929/,sentry-sample_rate=1.0,sentry-sampled=true', 'Accept': '/', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.9 aiohttp/3.7.4'}, 'data': None}, 'release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f', 'environment': 'production', 'server_name': 'runnervmrc6n4', 'sdk': {'name': 'sentry.python.aiohttp', 'version': '2.59.0', 'packages': [{'name': 'pypi:sentry-sdk', 'version': '2.59.0'}], 'integrations': ['aiohttp', 'argv', 'atexit', 'dedupe', 'excepthook', 'logging', 'modules', 'stdlib', 'threading']}, 'platform': 'python'}), UnwrappedItem(type='span', payload={'trace_id': '357daa0339ac4d38a585a0b806ac6cb2', 'span_id': 'ab82f4ee25431eae', 'name': 'GET http://127.0.0.1:41929/', 'status': 'error', 'is_segment': True, 'start_timestamp': 1778245934.837718, 'end_timestamp': 1778245934.84913, 'attributes': {'sentry.origin': 'auto.http.aiohttp', 'sentry.op': 'http.client', 'http.request.method': 'GET', 'url.full': 'http://127.0.0.1:41929/', 'thread.id': '139747850922880', 'thread.name': 'MainThread', 'process.command_args': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/main.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4'], 'http.response.status_code': 500, 'sentry.segment.id': 'ab82f4ee25431eae', 'sentry.segment.name': 'GET http://127.0.0.1:41929/', 'sentry.sdk.name': 'sentry.python.aiohttp', 'sentry.sdk.version': '2.59.0', 'server.address': 'runnervmrc6n4', 'sentry.environment': 'production', 'sentry.release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f'}})])

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1496: in test_server_error_span_streaming
    assert len(items) == 3
E   assert 2 == 3
E    +  where 2 = len([UnwrappedItem(type='event', payload={'level': 'error', 'exception': {'values': [{'mechanism': {'type': 'aiohttp', 'handled': False}, 'module': None, 'type': 'ZeroDivisionError', 'value': 'division by zero', 'stacktrace': {'frames': [{'filename': 'aiohttp/web_app.py', 'abs_path': '/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/aiohttp/web_app.py', 'function': '_handle', 'module': 'aiohttp.web_app', 'lineno': 499, 'pre_context': ['                                partial(m, handler=handler), handler', '                            )', '                        else:', '                            handler = await m(app, handler)  # type: ignore', ''], 'context_line': '            resp = await handler(request)', 'post_context': ['', '        return resp', '', '    def __call__(self) -> "Application":', '        """gunicorn compatibility"""'], 'vars': {'self': {}, 'request': {}, 'loop': '<_UnixSelectorEventLoop running=True closed=False debug=False>', 'debug': 'False', 'match_info': {}, 'resp': 'None', 'expect': 'None', 'handler': '<function test_server_error_span_streaming.<locals>.hello at 0x7f1991790430>'}, 'in_app': False}, {'filename': 'tests/integrations/aiohttp/test_aiohttp.py', 'abs_path': '/home/runner/work/sentry-python/sentry-python/tests/integrations/aiohttp/test_aiohttp.py', 'function': 'hello', 'module': 'tests.integrations.aiohttp.test_aiohttp', 'lineno': 1482, 'pre_context': ['        traces_sample_rate=1.0,', '        _experiments={"trace_lifecycle": "stream"},', '    )', '', '    async def hello(request):'], 'context_line': '        1 / 0', 'post_context': ['', '    app = web.Application()', '    app.router.add_get("/", hello)', '', '    items = capture_items("event", "span")'], 'vars': {'request': {}}, 'in_app': True}]}}]}, 'event_id': '595dd3acd8fb47ceb8b815b13297740f', 'timestamp': '2026-05-08T13:12:14.841597Z', 'contexts': {'trace': {'trace_id': '357daa0339ac4d38a585a0b806ac6cb2', 'span_id': 'b1e93bf9c589f2e8', 'parent_span_id': 'ab82f4ee25431eae', 'op': 'http.server', 'origin': 'auto.http.aiohttp'}, 'runtime': {'name': 'CPython', 'version': '3.9.25', 'build': '3.9.25 (main, Nov  3 2025, 15:14:54) \n[GCC 11.4.0]'}}, 'transaction': 'tests.integrations.aiohttp.test_aiohttp.test_server_error_span_streaming.<locals>.hello', 'transaction_info': {'source': <TransactionSource.COMPONENT: 'component'>}, 'breadcrumbs': {'values': []}, 'extra': {'sys.argv': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/__main__.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4']}, 'modules': {'sentry-sdk': '2.59.0', 'pytest-aiohttp': '0.3.0', 'multidict': '6.7.1', 'iniconfig': '2.1.0', 'pytest-forked': '1.6.0', 'charset-normalizer': '3.4.7', 'jsonschema': '4.25.1', 'wheel': '0.43.0', 'propcache': '0.4.1', 'tomli': '2.4.1', 'pyyaml': '6.0.3', 'coverage': '7.10.7', 'pytest-localserver': '0.10.0', 'certifi': '2026.4.22', 'hyperframe': '6.1.0', 'colorama': '0.4.6', 'pygments': '2.20.0', 'markupsafe': '3.0.3', 'referencing': '0.36.2', 'pysocks': '1.7.1', 'setuptools': '69.5.1', 'httpcore': '1.0.9', 'urllib3': '2.6.3', 'yarl': '1.22.0', 'h2': '4.3.0', 'hpack': '4.1.0', 'pytest-timeout': '2.4.0', 'asttokens': '3.0.1', 'idna': '3.13', 'py': '1.11.0', 'async-timeout': '3.0.1', 'pytest-watch': '4.2.0', 'pluggy': '1.6.0', 'aiohttp': '3.7.4', 'watchdog': '6.0.0', 'brotli': '1.2.0', 'pytest-cov': '7.1.0', 'responses': '0.26.0', 'socksio': '1.0.0', 'pip': '24.0', 'requests': '2.32.5', 'docopt': '0.6.2', 'typing_extensions': '4.15.0', 'docker': '7.1.0', 'executing': '2.2.1', 'werkzeug': '3.1.8', 'jsonschema-specifications': '2025.9.1', 'h11': '0.16.0', 'packaging': '26.2', 'chardet': '3.0.4', 'attrs': '26.1.0', 'rpds-py': '0.27.1', 'pytest': '8.4.2', 'exceptiongroup': '1.3.1'}, 'request': {'url': 'http://127.0.0.1:41929/', 'query_string': '', 'method': 'GET', 'env': {'REMOTE_ADDR': '127.0.0.1'}, 'headers': {'Host': '127.0.0.1:41929', 'sentry-trace': '357daa0339ac4d38a585a0b806ac6cb2-ab82f4ee25431eae-1', 'baggage': 'sentry-trace_id=357daa0339ac4d38a585a0b806ac6cb2,sentry-sample_rand=0.034682,sentry-environment=production,sentry-release=fe5b14821f6fcc5acfdab3744c00cc8d3876e65f,sentry-transaction=GET%20http%3A//127.0.0.1%3A41929/,sentry-sample_rate=1.0,sentry-sampled=true', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.9 aiohttp/3.7.4'}, 'data': None}, 'release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f', 'environment': 'production', 'server_name': 'runnervmrc6n4', 'sdk': {'name': 'sentry.python.aiohttp', 'version': '2.59.0', 'packages': [{'name': 'pypi:sentry-sdk', 'version': '2.59.0'}], 'integrations': ['aiohttp', 'argv', 'atexit', 'dedupe', 'excepthook', 'logging', 'modules', 'stdlib', 'threading']}, 'platform': 'python'}), UnwrappedItem(type='span', payload={'trace_id': '357daa0339ac4d38a585a0b806ac6cb2', 'span_id': 'ab82f4ee25431eae', 'name': 'GET http://127.0.0.1:41929/', 'status': 'error', 'is_segment': True, 'start_timestamp': 1778245934.837718, 'end_timestamp': 1778245934.84913, 'attributes': {'sentry.origin': 'auto.http.aiohttp', 'sentry.op': 'http.client', 'http.request.method': 'GET', 'url.full': 'http://127.0.0.1:41929/', 'thread.id': '139747850922880', 'thread.name': 'MainThread', 'process.command_args': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/__main__.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4'], 'http.response.status_code': 500, 'sentry.segment.id': 'ab82f4ee25431eae', 'sentry.segment.name': 'GET http://127.0.0.1:41929/', 'sentry.sdk.name': 'sentry.python.aiohttp', 'sentry.sdk.version': '2.59.0', 'server.address': 'runnervmrc6n4', 'sentry.environment': 'production', 'sentry.release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f'}})])

test_http_exception_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 403 + where 500 = <ClientResponse(http://127.0.0.1:33723/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:15 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1542: in test_http_exception_span_streaming
    assert resp.status == 403
E   AssertionError: assert 500 == 403
E    +  where 500 = <ClientResponse(http://127.0.0.1:33723/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:15 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_http_exception_ok_status_not_overridden_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 500 == 302 + where 500 = <ClientResponse(http://127.0.0.1:41277/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:15 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1580: in test_http_exception_ok_status_not_overridden_span_streaming
    assert resp.status == 302
E   AssertionError: assert 500 == 302
E    +  where 500 = <ClientResponse(http://127.0.0.1:41277/) [500 Internal Server Error]>\n<CIMultiDictProxy('Content-Type': 'text/plain; charset=utf-8', 'Content-Length': '55', 'Date': 'Fri, 08 May 2026 13:12:15 GMT', 'Server': 'Python/3.9 aiohttp/3.7.4', 'Connection': 'close')>\n.status

test_outgoing_client_span_span_streaming[pyloop]

File: tests.integrations.aiohttp.test_aiohttp
Suite: py3.9-aiohttp-v3.7.4
Error: AssertionError: assert 1 == 3 + where 1 = len([UnwrappedItem(type='span', payload={'trace_id': '96650ac078bc44d3a53c8b0a24c75a6c', 'span_id': '9bce2b81809406c2', 'name': 'GET http://127.0.0.1:41523/', 'status': 'error', 'is_segment': True, 'start_timestamp': 1778245935.378089, 'end_timestamp': 1778245935.623357, 'attributes': {'sentry.origin': 'auto.http.aiohttp', 'sentry.op': 'http.client', 'http.request.method': 'GET', 'url.full': 'http://127.0.0.1:41523/', 'thread.id': '139747850922880', 'thread.name': 'MainThread', 'process.command_args': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/main.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4'], 'http.response.status_code': 500, 'code.line.number': 1624, 'code.namespace': 'tests.integrations.aiohttp.test_aiohttp', 'code.file.path': 'tests/integrations/aiohttp/test_aiohttp.py', 'code.function': 'test_outgoing_client_span_span_streaming', 'sentry.segment.id': '9bce2b81809406c2', 'sentry.segment.name': 'GET http://127.0.0.1:41523/', 'sentry.sdk.name': 'sentry.python.aiohttp', 'sentry.sdk.version': '2.59.0', 'server.address': 'runnervmrc6n4', 'sentry.environment': 'production', 'sentry.release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f'}})])

Stack Trace
tests/integrations/aiohttp/test_aiohttp.py:1632: in test_outgoing_client_span_span_streaming
    assert len(items) == 3
E   AssertionError: assert 1 == 3
E    +  where 1 = len([UnwrappedItem(type='span', payload={'trace_id': '96650ac078bc44d3a53c8b0a24c75a6c', 'span_id': '9bce2b81809406c2', 'name': 'GET http://127.0.0.1:41523/', 'status': 'error', 'is_segment': True, 'start_timestamp': 1778245935.378089, 'end_timestamp': 1778245935.623357, 'attributes': {'sentry.origin': 'auto.http.aiohttp', 'sentry.op': 'http.client', 'http.request.method': 'GET', 'url.full': 'http://127.0.0.1:41523/', 'thread.id': '139747850922880', 'thread.name': 'MainThread', 'process.command_args': ['/home/runner/work/sentry-python/sentry-python/.tox/py3.9-aiohttp-v3.7.4/lib/python3.9/site-packages/pytest/__main__.py', '-W', 'error::pytest.PytestUnraisableExceptionWarning', 'tests/integrations/aiohttp', '-o', 'junit_suite_name=py3.9-aiohttp-v3.7.4'], 'http.response.status_code': 500, 'code.line.number': 1624, 'code.namespace': 'tests.integrations.aiohttp.test_aiohttp', 'code.file.path': 'tests/integrations/aiohttp/test_aiohttp.py', 'code.function': 'test_outgoing_client_span_span_streaming', 'sentry.segment.id': '9bce2b81809406c2', 'sentry.segment.name': 'GET http://127.0.0.1:41523/', 'sentry.sdk.name': 'sentry.python.aiohttp', 'sentry.sdk.version': '2.59.0', 'server.address': 'runnervmrc6n4', 'sentry.environment': 'production', 'sentry.release': 'fe5b14821f6fcc5acfdab3744c00cc8d3876e65f'}})])

❌ Patch coverage is 45.00%. Project has 16033 uncovered lines.

Files with missing lines (3)
File Patch % Lines
utils.py 54.32% ⚠️ 428 Missing and 90 partials
client.py 61.82% ⚠️ 210 Missing and 78 partials
consts.py 99.22% ⚠️ 2 Missing

Generated by Codecov Action

Comment thread sentry_sdk/_span_batcher.py Outdated
Comment thread sentry_sdk/client.py Outdated
Comment thread sentry_sdk/client.py Outdated
Comment thread sentry_sdk/client.py Outdated
Comment thread sentry_sdk/client.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add before_send_span

1 participant