Repository navigation
fix(dart): Count streamed spans in client reports - #4097
Conversation
Map the `span` envelope item type to the `span` data category so dropped span-streaming envelopes record one outcome per contained span instead of a single `unknown` outcome. This also makes `span` rate limits apply to span envelope items. Per-item recording now lives in `TransportUtils.recordLostItem`, shared by the HTTP transport and the rate limiter. Co-Authored-By: Gino Buenaflor <giancarlo.buenaflor@sentry.io>
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. Fixes
DependenciesDeps
Internal Changes
🤖 This preview updates automatically when you update the PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4097 +/- ##
==========================================
- Coverage 88.81% 88.80% -0.02%
==========================================
Files 348 348
Lines 12631 12627 -4
==========================================
- Hits 11218 11213 -5
- Misses 1413 1414 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
There was a problem hiding this comment.
🟢 Approval recommended
There are no active review issues for the streamed-span client-reporting changes.
No open issues 🎉
What changed in this PR
This PR fixes streamed-span client reporting in the Dart SDK’s HTTP transport path, so discarded spans are counted individually and span-specific rate limits apply.
Changes:
- Maps
spanenvelope items toDataCategory.span. - Centralizes dropped-item accounting for transport failures and rate limiting.
- Adds regression tests for span categorization and three-span discard counts.
| File | Description |
|---|---|
packages/dart/test/transport/rate_limiter_test.dart |
Tests span categorization, rate-limit filtering, and discarded-span counts. |
packages/dart/test/transport/http_transport_test.dart |
Tests discarded-span counts after a network failure. |
packages/dart/lib/src/transport/transport_utils.dart |
Adds shared dropped-item accounting using span item counts. |
packages/dart/lib/src/transport/rate_limiter.dart |
Reuses shared accounting for rate-limited items. |
packages/dart/lib/src/transport/data_category.dart |
Maps the span item type to its client-report category. |
Review effort: Balanced
📜 Description
DataCategory.fromItemTypehad no case for thespanenvelope item type (span streaming /span.v2), so it fell through toDataCategory.unknown. As a result:network_error/send_error), it was recorded as 1 outcome with categoryunknown, not N outcomes with categoryspan.spanrate limit, becauseRateLimiter._isRetryAfterskipsunknowncategories. Only__all__limits applied.This PR:
'span'→DataCategory.span.TransportUtils.recordLostItem, which records one dropped envelope item and counts every telemetry item it contains (log_item/log_byte,trace_metric/trace_metric_byte,spanviaitemCount, and transaction child spans).HttpTransport(throughrecordLostEvents) andRateLimiter.filterboth call it, so there's one copy of this branching instead of two.💡 Motivation and Context
This aligns with the develop-docs clarification in getsentry/sentry-docs#19854 ("Quantity of Discarded Envelopes" in client-reports spec 1.25.0, and the "Client Reports" section in spans spec 1.1.0): the quantity must be the number of discarded spans, not the number of envelopes or envelope items. Logs and metrics already did this. Spans were the gap.
This only covers the Dart
HttpTransportpath. On Flutter mobile, envelopes go to the native SDK throughFileSystemTransport, so the native SDK records send failures there.Not in scope: the new spans spec also lists a
no_parent_spandiscard reason, which doesn't exist inDiscardReasonyet.💚 How did you test it?
fromItemType('span'), aspanrate limit dropping a 3-span envelope with quantity 3, and a network error on a 3-span envelope recordingspanquantity 3.dart testinpackages/dart(VM): all 1713 tests pass.dart analyzeanddart format --set-exit-if-changedare clean with Dart 3.13.5.📝 Checklist
sendDefaultPiiis enabledThe changes are internal (
TransportUtilsisn't exported). Behavior change:spanrate limits now drop span-streaming envelope items, as the spec requires.🔮 Next steps
no_parent_spandiscard reason and record it.via Gino Buenaflor.
--
View Junior Session [Sentry]