feat: Report blocked_main_thread on streaming spans#3821
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. FeaturesDart
Other
Fixes
Enhancements
DependenciesDeps
Internal Changes
🤖 This preview updates automatically when you update the PR. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3821 +/- ##
==========================================
- Coverage 87.34% 87.28% -0.06%
==========================================
Files 337 338 +1
Lines 12205 12250 +45
==========================================
+ Hits 10660 10692 +32
- Misses 1545 1558 +13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Android Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f3d7a42 | 358.26 ms | 343.32 ms | -14.94 ms |
| a909995 | 383.55 ms | 370.78 ms | -12.77 ms |
| 5b9a0da | 446.94 ms | 449.22 ms | 2.28 ms |
| d2356d0 | 363.06 ms | 349.96 ms | -13.11 ms |
| 6f47800 | 451.04 ms | 509.64 ms | 58.60 ms |
| 20faa47 | 400.26 ms | 392.90 ms | -7.37 ms |
| d15266b | 372.77 ms | 363.83 ms | -8.94 ms |
| e45c0e1 | 447.29 ms | 558.33 ms | 111.04 ms |
| dc53d48 | 358.91 ms | 366.17 ms | 7.26 ms |
| a7f011a | 378.33 ms | 381.58 ms | 3.25 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f3d7a42 | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| a909995 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| 5b9a0da | 13.93 MiB | 14.93 MiB | 1.00 MiB |
| d2356d0 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| 6f47800 | 6.54 MiB | 7.69 MiB | 1.15 MiB |
| 20faa47 | 13.93 MiB | 15.18 MiB | 1.25 MiB |
| d15266b | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| e45c0e1 | 6.54 MiB | 7.70 MiB | 1.16 MiB |
| dc53d48 | 14.09 MiB | 15.28 MiB | 1.19 MiB |
| a7f011a | 14.31 MiB | 15.49 MiB | 1.19 MiB |
Previous results on branch: feat/thread-info-streaming-spans
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1819dbb | 355.28 ms | 357.22 ms | 1.95 ms |
| ae2dfff | 362.20 ms | 371.57 ms | 9.37 ms |
| 5b8274d | 352.13 ms | 343.96 ms | -8.17 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1819dbb | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| ae2dfff | 14.55 MiB | 15.87 MiB | 1.31 MiB |
| 5b8274d | 14.55 MiB | 15.87 MiB | 1.31 MiB |
iOS Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 192b44c | 1269.08 ms | 1275.52 ms | 6.44 ms |
| eca355d | 1238.39 ms | 1266.98 ms | 28.59 ms |
| 79f6b41 | 1269.33 ms | 1279.71 ms | 10.38 ms |
| c26ed0a | 1244.11 ms | 1263.85 ms | 19.75 ms |
| ea06d23 | 1254.02 ms | 1252.60 ms | -1.42 ms |
| a2c8611 | 1253.83 ms | 1246.92 ms | -6.91 ms |
| f42e9fb | 1247.60 ms | 1255.89 ms | 8.29 ms |
| d052aef | 1246.33 ms | 1253.04 ms | 6.71 ms |
| de377fd | 1252.28 ms | 1254.76 ms | 2.48 ms |
| dc53d48 | 1252.06 ms | 1255.61 ms | 3.55 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 192b44c | 5.53 MiB | 5.96 MiB | 444.33 KiB |
| eca355d | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| 79f6b41 | 7.86 MiB | 9.44 MiB | 1.58 MiB |
| c26ed0a | 5.53 MiB | 5.97 MiB | 453.76 KiB |
| ea06d23 | 5.53 MiB | 5.96 MiB | 443.26 KiB |
| a2c8611 | 5.66 MiB | 6.10 MiB | 452.11 KiB |
| f42e9fb | 5.83 MiB | 6.28 MiB | 462.32 KiB |
| d052aef | 5.73 MiB | 6.17 MiB | 453.76 KiB |
| de377fd | 20.71 MiB | 22.43 MiB | 1.73 MiB |
| dc53d48 | 5.65 MiB | 6.09 MiB | 446.96 KiB |
Previous results on branch: feat/thread-info-streaming-spans
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ae2dfff | 1252.02 ms | 1260.24 ms | 8.22 ms |
| 1819dbb | 1247.45 ms | 1253.34 ms | 5.89 ms |
| 5b8274d | 1265.18 ms | 1268.00 ms | 2.82 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ae2dfff | 5.83 MiB | 6.28 MiB | 459.91 KiB |
| 1819dbb | 5.83 MiB | 6.28 MiB | 459.94 KiB |
| 5b8274d | 5.83 MiB | 6.28 MiB | 459.87 KiB |
5b8274d to
1819dbb
Compare
1819dbb to
5b8274d
Compare
5b8274d to
ae2dfff
Compare
ThreadInfoIntegration only handled v1 spans, so streaming/v2 spans got no thread.id/thread.name and never got blocked_main_thread. The internal sync marker set by the file/hive/isar instrumentation also leaked to Sentry on v2, because nothing consumed it there. The integration now branches on traceLifecycle: in streaming mode it sets thread info via OnSpanStartV2 and derives blocked_main_thread via OnProcessSpan, mirroring the v1 path. The raw 'sync' data key is wrapped in markSynchronous / isSynchronous / clearSynchronous extensions, so instrumentation states the fact and the integration stays the sole setter of blocked_main_thread and strips the marker before send. Refs GH-3487 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
ae2dfff to
59370d0
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates tracing so streaming/v2 spans receive the same thread metadata as v1 spans and can derive blocked_main_thread from a shared internal “synchronous operation” marker, while ensuring that marker is stripped before sending data to Sentry.
Changes:
- Add
OnSpanStartV2/OnProcessSpanhandling inThreadInfoIntegrationto populatethread.id/thread.nameand deriveblocked_main_threadfor streaming spans. - Centralize the internal synchronous marker (
sync) behind internal extensions (markSynchronous,isSynchronous,clearSynchronous) and migrate auto-instrumentation to use them. - Move thread-related keys to
SemanticAttributesConstantsand update tests accordingly.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/flutter/lib/src/integrations/thread_info_integration.dart | Adds streaming lifecycle support for thread info + blocked_main_thread derivation (but currently contains a Dart switch compile error). |
| packages/flutter/test/integrations/thread_info_integration_test.dart | Extends coverage to streaming spans and updates expectations to SemanticAttributesConstants. |
| packages/dart/lib/src/tracing/instrumentation/instrumentation_span.dart | Introduces internal extensions for marking/reading/clearing the synchronous marker across v1/v2 spans. |
| packages/file/lib/src/sentry_file.dart | Switches sync span instrumentation to markSynchronous(). |
| packages/hive/lib/src/sentry_span_helper.dart | Switches sync span instrumentation to markSynchronous(). |
| packages/isar/lib/src/sentry_span_helper.dart | Switches sync span instrumentation to markSynchronous(). |
| packages/dart/lib/src/span_data_convention.dart | Removes thread-related constants (this is a breaking public API change as-is). |
| packages/dart/lib/src/constants.dart | Adds thread-related semantic attribute constants (thread.id, thread.name, blocked_main_thread). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
denrase
left a comment
There was a problem hiding this comment.
LGTM, smaller feedback notes.
The ThreadInfoIntegration handlers only stripped the internal 'sync' marker when it equaled true, so a stray non-true value would leak to Sentry. Gate on marker presence and clear it unconditionally, while still setting blocked_main_thread only when the span is actually synchronous. Also move the synchronous-marker extensions and their shared private key out of instrumentation_span.dart into a dedicated synchronous_span_marker.dart, so the raw key stays in one place. No public API or v1 behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Removed TODO comment about adding other data keys.
v10-branch #3847 added a Hint parameter to OnProcessSpan while the thread info tests from #3821 landed in parallel still using the single-argument constructor, breaking compilation on the base branch. Pass an empty Hint like the other call sites. Co-Authored-By: Claude Fable 5 <[email protected]>
* ref(dart)!: Make feature flags hub/scope-based Move the feature-flag buffer logic off FeatureFlagsIntegration and onto Scope/Hub, mirroring the addBreadcrumb path. Sentry.addFeatureFlag now delegates through the hub instead of reaching into options.integrations. FeatureFlagsIntegration is deleted, so events no longer report "FeatureFlagsIntegration" in sdk.integrations. Usage is now tracked via the "featureFlags" entry in sdk.features, recorded on actual use. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * ref(dart): Read feature flags context field directly Avoid copying the whole contexts map via the public getter on each addFeatureFlag call; read the internal _contexts field instead. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * test(flutter): Pass Hint to OnProcessSpan in thread info tests v10-branch #3847 added a Hint parameter to OnProcessSpan while the thread info tests from #3821 landed in parallel still using the single-argument constructor, breaking compilation on the base branch. Pass an empty Hint like the other call sites. Co-Authored-By: Claude Fable 5 <[email protected]> --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
ThreadInfoIntegrationonly handled v1 spans (OnSpanStart/OnSpanFinish), so streaming/v2 spans received nothread.id/thread.nameand never gotblocked_main_thread. The internalsyncmarker set by thefile/hive/isarinstrumentation was also written onto v2 spans but never consumed there, so it leaked to Sentry.This brings v2/streaming spans to parity with v1.
call()/close()branch onoptions.traceLifecycle:OnSpanStart/OnSpanFinish(unchanged).OnSpanStartV2setsthread.id/thread.name;OnProcessSpanderivesblocked_main_threadfrom the sync marker when on the main isolate, then strips the marker.The responsibilities stay clean: instrumentation states a fact it knows (the op is synchronous), and
ThreadInfoIntegration— which knows the isolate — is the sole setter ofblocked_main_thread. The previously raw'sync'data key is wrapped in a small set of internal extensions so the key lives in one place:InstrumentationSpan.markSynchronous()— used byfile/hive/isar.SentrySpan.isSynchronous/clearSynchronous()(v1) andSentrySpanV2.isSynchronous/clearSynchronous()(v2) — used by the integration.No new state is added to the span classes. Behavior is unchanged on v1.