Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@sentrivana
Copy link
Contributor

@sentrivana sentrivana commented Jan 30, 2026

  • Add a specialized SpanBatcher that batches and sends spans by trace ID. Hook it up to the client.
  • Add a skeleton of a new StreamedSpan class that will eventually replace the current Span class.

Chipping away at #5317 to transform it into reviewable and mergeable PRs.

@sentrivana sentrivana changed the title Ivana/span first/span batcher feat(span-streaming): Add a span batcher (2) Jan 30, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 30, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Span Streaming

  • feat(span-streaming): Add span batcher (2) by sentrivana in #5398
  • feat(span-streaming): Add experimental trace_lifecycle switch (1) by sentrivana in #5397

Bug Fixes 🐛

  • fix(arq): handle settings_cls passed as keyword argument by nc9 in #5393
  • fix(dramatiq): cleanup isolated scope and transaction when message is skipped by frankie567 in #5346
  • fix(google-genai): deactivate google genai when langchain is used by shellmayr in #5389

Internal Changes 🔧

  • ci: migration to the new codecov action by MathurAditya724 in #5392

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 30, 2026

Codecov Results 📊

14 passed | Total: 14 | Pass Rate: 100% | Execution Time: 3.66s

All tests are passing successfully.

❌ Patch coverage is 33.33%. Project has 14761 uncovered lines.

Files with missing lines (181)
File Patch % Lines
utils.py 30.63% ⚠️ 634 Missing and 36 partials
langchain.py 3.28% ⚠️ 590 Missing
openai.py 5.63% ⚠️ 486 Missing
utils.py 0.00% ⚠️ 479 Missing
tracing_utils.py 41.05% ⚠️ 349 Missing and 32 partials
__init__.py 5.08% ⚠️ 374 Missing
scope.py 65.01% ⚠️ 282 Missing and 73 partials
starlette.py 5.34% ⚠️ 337 Missing
transport.py 23.29% ⚠️ 303 Missing and 2 partials
client.py 54.84% ⚠️ 224 Missing and 55 partials
mcp.py 4.85% ⚠️ 255 Missing
anthropic.py 9.43% ⚠️ 240 Missing
transaction_profiler.py 35.52% ⚠️ 216 Missing and 10 partials
__init__.py 3.93% ⚠️ 220 Missing
utils.py 16.34% ⚠️ 215 Missing
langgraph.py 5.29% ⚠️ 215 Missing
tracing.py 65.26% ⚠️ 165 Missing and 42 partials
span_processor.py 0.00% ⚠️ 205 Missing
__init__.py 5.14% ⚠️ 203 Missing
continuous_profiler.py 43.77% ⚠️ 176 Missing and 16 partials
strawberry.py 8.54% ⚠️ 182 Missing
aws_lambda.py 16.50% ⚠️ 167 Missing
spark_driver.py 0.00% ⚠️ 166 Missing
huggingface_hub.py 8.89% ⚠️ 164 Missing
sanic.py 9.60% ⚠️ 160 Missing
aiohttp.py 10.84% ⚠️ 148 Missing
cloud_resource_context.py 0.00% ⚠️ 145 Missing
ai_client.py 0.00% ⚠️ 145 Missing
rust_tracing.py 0.00% ⚠️ 143 Missing
litellm.py 0.00% ⚠️ 138 Missing
litestar.py 9.59% ⚠️ 132 Missing
starlite.py 8.33% ⚠️ 132 Missing
envelope.py 40.82% ⚠️ 116 Missing and 11 partials
falcon.py 8.94% ⚠️ 112 Missing
flask.py 12.50% ⚠️ 112 Missing
spotlight.py 28.47% ⚠️ 103 Missing and 8 partials
asgi.py 20.71% ⚠️ 111 Missing
cohere.py 12.70% ⚠️ 110 Missing
dramatiq.py 0.00% ⚠️ 110 Missing
agent_run.py 0.00% ⚠️ 110 Missing
arq.py 9.92% ⚠️ 109 Missing
asgi.py 0.00% ⚠️ 109 Missing
hub.py 45.60% ⚠️ 105 Missing and 3 partials
logging.py 32.68% ⚠️ 103 Missing and 3 partials
pymongo.py 10.17% ⚠️ 106 Missing
beat.py 8.62% ⚠️ 106 Missing
caching.py 0.00% ⚠️ 106 Missing
utils.py 0.00% ⚠️ 103 Missing
templates.py 0.00% ⚠️ 100 Missing
quart.py 16.10% ⚠️ 99 Missing
wsgi.py 22.66% ⚠️ 99 Missing
gcp.py 0.00% ⚠️ 98 Missing
otlp.py 0.00% ⚠️ 97 Missing
utils.py 13.39% ⚠️ 97 Missing
sessions.py 27.82% ⚠️ 96 Missing
pyramid.py 13.76% ⚠️ 94 Missing
tornado.py 14.55% ⚠️ 94 Missing
__init__.py 0.00% ⚠️ 93 Missing
models.py 5.15% ⚠️ 92 Missing
_wsgi_common.py 28.35% ⚠️ 91 Missing
bottle.py 11.65% ⚠️ 91 Missing
middleware.py 0.00% ⚠️ 90 Missing
agent_run.py 0.00% ⚠️ 90 Missing
stdlib.py 35.82% ⚠️ 86 Missing and 1 partials
beam.py 0.00% ⚠️ 84 Missing
loguru.py 11.58% ⚠️ 84 Missing
ray.py 0.00% ⚠️ 84 Missing
asyncio.py 0.00% ⚠️ 80 Missing
invoke_agent.py 0.00% ⚠️ 79 Missing
runner.py 0.00% ⚠️ 77 Missing
session.py 15.56% ⚠️ 76 Missing
clickhouse_driver.py 17.58% ⚠️ 75 Missing
pure_eval.py 0.00% ⚠️ 73 Missing
worker.py 22.58% ⚠️ 72 Missing
ariadne.py 14.46% ⚠️ 71 Missing
gql.py 10.13% ⚠️ 71 Missing
fastapi.py 15.85% ⚠️ 69 Missing
monitoring.py 17.07% ⚠️ 68 Missing
graphene.py 12.82% ⚠️ 68 Missing
transactions.py 0.00% ⚠️ 67 Missing
_queue.py 26.67% ⚠️ 66 Missing
rq.py 15.38% ⚠️ 66 Missing
streaming.py 0.00% ⚠️ 66 Missing
huey.py 17.72% ⚠️ 65 Missing
boto3.py 14.86% ⚠️ 63 Missing
api.py 59.06% ⚠️ 61 Missing
httpx.py 16.44% ⚠️ 61 Missing
chalice.py 16.18% ⚠️ 57 Missing
propagator.py 0.00% ⚠️ 57 Missing
server.py 0.00% ⚠️ 56 Missing
spark_worker.py 0.00% ⚠️ 56 Missing
graph_nodes.py 0.00% ⚠️ 52 Missing
gnu_backtrace.py 0.00% ⚠️ 51 Missing
socket.py 0.00% ⚠️ 50 Missing
views.py 0.00% ⚠️ 50 Missing
tools.py 0.00% ⚠️ 49 Missing
_batcher.py 41.25% ⚠️ 47 Missing
serializer.py 82.80% ⚠️ 32 Missing and 13 partials
_asgi_common.py 16.67% ⚠️ 45 Missing
signals_handlers.py 0.00% ⚠️ 44 Missing
invoke_agent.py 0.00% ⚠️ 43 Missing
utils.py 22.22% ⚠️ 42 Missing and 1 partials
client.py 0.00% ⚠️ 40 Missing
executing.py 0.00% ⚠️ 38 Missing
client.py 0.00% ⚠️ 38 Missing
serverless.py 0.00% ⚠️ 36 Missing
server.py 0.00% ⚠️ 35 Missing
_span_batcher.py 37.04% ⚠️ 34 Missing
sys_exit.py 0.00% ⚠️ 32 Missing
launchdarkly.py 0.00% ⚠️ 31 Missing
threading.py 76.84% ⚠️ 22 Missing and 8 partials
trytond.py 0.00% ⚠️ 30 Missing
tools.py 0.00% ⚠️ 30 Missing
integration.py 0.00% ⚠️ 30 Missing
error_tracing.py 0.00% ⚠️ 29 Missing
scrubber.py 73.91% ⚠️ 18 Missing and 10 partials
_werkzeug.py 11.11% ⚠️ 24 Missing
typer.py 0.00% ⚠️ 24 Missing
tasks.py 0.00% ⚠️ 24 Missing
_compat.py 41.03% ⚠️ 23 Missing
monitor.py 67.21% ⚠️ 20 Missing and 3 partials
__init__.py 84.78% ⚠️ 14 Missing and 9 partials
sqlalchemy.py 84.62% ⚠️ 12 Missing and 11 partials
statsig.py 0.00% ⚠️ 23 Missing
execute_tool.py 0.00% ⚠️ 23 Missing
logger.py 43.59% ⚠️ 22 Missing
decorator.py 37.14% ⚠️ 22 Missing
ai_client.py 15.38% ⚠️ 22 Missing
_log_batcher.py 0.00% ⚠️ 21 Missing
attachments.py 27.59% ⚠️ 21 Missing
dedupe.py 55.00% ⚠️ 18 Missing and 3 partials
unraisablehook.py 0.00% ⚠️ 21 Missing
__init__.py 8.70% ⚠️ 21 Missing
openfeature.py 0.00% ⚠️ 20 Missing
execute_tool.py 0.00% ⚠️ 20 Missing
unleash.py 0.00% ⚠️ 19 Missing
_lru_cache.py 43.33% ⚠️ 17 Missing and 1 partials
_openai_completions_api.py 21.74% ⚠️ 18 Missing
model_request.py 0.00% ⚠️ 18 Missing
utils.py 0.00% ⚠️ 16 Missing
atexit.py 56.25% ⚠️ 14 Missing and 1 partials
excepthook.py 56.25% ⚠️ 14 Missing and 1 partials
feature_flags.py 56.25% ⚠️ 14 Missing
_init_implementation.py 45.83% ⚠️ 13 Missing
__init__.py 27.78% ⚠️ 13 Missing
types.py 0.00% ⚠️ 12 Missing
traces.py 0.00% ⚠️ 11 Missing
_types.py 66.67% ⚠️ 10 Missing
api.py 37.50% ⚠️ 10 Missing
utils.py 41.18% ⚠️ 10 Missing
utils.py 94.67% ⚠️ 4 Missing and 6 partials
metrics.py 47.06% ⚠️ 9 Missing
caches.py 93.22% ⚠️ 4 Missing and 5 partials
asyncpg.py 96.43% ⚠️ 4 Missing and 4 partials
_metrics_batcher.py 65.00% ⚠️ 7 Missing
handoff.py 0.00% ⚠️ 7 Missing
consts.py 0.00% ⚠️ 7 Missing
redis_py_cluster_legacy.py 53.33% ⚠️ 7 Missing
_openai_responses_api.py 33.33% ⚠️ 6 Missing
redis_cluster.py 88.24% ⚠️ 4 Missing and 2 partials
debug.py 91.30% ⚠️ 2 Missing and 2 partials
consts.py 0.00% ⚠️ 4 Missing
__init__.py 20.00% ⚠️ 4 Missing
__init__.py 0.00% ⚠️ 4 Missing
_async_common.py 96.08% ⚠️ 2 Missing and 2 partials
_sync_common.py 96.00% ⚠️ 2 Missing and 2 partials
queries.py 93.55% ⚠️ 2 Missing and 2 partials
__init__.py 0.00% ⚠️ 3 Missing
__init__.py 40.00% ⚠️ 3 Missing
__init__.py 0.00% ⚠️ 3 Missing
__init__.py 0.00% ⚠️ 3 Missing
rb.py 70.00% ⚠️ 3 Missing
redis.py 85.00% ⚠️ 3 Missing
__init__.py 0.00% ⚠️ 3 Missing
consts.py 99.43% ⚠️ 2 Missing
argv.py 100.00% ⚠️ 2 partials
modules.py 94.12% ⚠️ 1 Missing and 1 partials
agent_workflow.py 71.43% ⚠️ 2 Missing
__init__.py 93.10% ⚠️ 2 Missing
consts.py 0.00% ⚠️ 1 Missing
consts.py 0.00% ⚠️ 1 Missing

Generated by Codecov Action

@sentrivana sentrivana changed the title feat(span-streaming): Add a span batcher (2) feat(span-streaming): Add span batcher (2) Jan 30, 2026
@sentrivana sentrivana marked this pull request as ready for review January 30, 2026 12:18
@sentrivana sentrivana requested a review from a team as a code owner January 30, 2026 12:18
"sent_at": format_timestamp(datetime.now(timezone.utc)),
"trace": dsc,
}
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Envelope header unconditionally includes null trace context

Low Severity

The _flush method unconditionally includes "trace": dsc in envelope headers even when dsc is None. This results in "trace": null in the serialized JSON. The established pattern elsewhere in the codebase (e.g., in client.py around line 909) is to only include the trace header when the dynamic sampling context is truthy. Including a null trace header is inconsistent and could potentially cause issues with the Sentry backend when this experimental feature is enabled.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All coming in future PRs

Base automatically changed from ivana/span-first/introduce-options to master January 30, 2026 12:30
Copy link
Contributor

@alexander-alderman-webb alexander-alderman-webb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good! just one question from me, not blocking

self._flusher_pid: "Optional[int]" = None

def get_size(self) -> int:
# caller is responsible for locking before checking this
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why can we not, or should we not, lock for the caller here?

Copy link
Contributor Author

@sentrivana sentrivana Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The add() function that needs to call this needs to lock a bigger chunk of code including this check and it can't really be split apart.

get_size() is now only used from add(), but if we ever need to use it from elsewhere too, I think it's likely that that place will also need to already be holding a lock if it's doing anything that depends on the current size of the buffer, so it makes sense that the responsibility to lock would be on the caller.

@sentrivana sentrivana enabled auto-merge (squash) February 2, 2026 09:19
@sentrivana sentrivana disabled auto-merge February 2, 2026 09:19
@sentrivana sentrivana enabled auto-merge (squash) February 2, 2026 09:20
@sentrivana sentrivana merged commit 67721df into master Feb 2, 2026
163 of 165 checks passed
@sentrivana sentrivana deleted the ivana/span-first/span-batcher branch February 2, 2026 09:27
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

if TYPE_CHECKING:
from typing import Any, Callable, Optional
from sentry_sdk.traces import StreamedSpan
from sentry_sdk._types import SerializedAttributeValue
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports clutter the new file

Low Severity

Several imports are never used in this file: SPANSTATUS (line 7), serialize_attribute and safe_repr (line 9), and SerializedAttributeValue (line 14). These imports are likely copy-pasted from another batcher but not yet needed.

Fix in Cursor Fix in Web

FLUSH_WAIT_TIME = 5.0

TYPE = "span"
CONTENT_TYPE = "application/vnd.sentry.items.span.v2+json"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class constants defined but never used

Low Severity

TYPE = "span" and CONTENT_TYPE = "..." class constants are defined but never used. The _flush() method hardcodes these same values at lines 97-98 instead of using self.TYPE and self.CONTENT_TYPE.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants