feat: Add strict trace continuation support#5136
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨
🤖 This preview updates automatically when you update the PR. |
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| abfcc92 | 309.54 ms | 380.32 ms | 70.78 ms |
| b3d8889 | 371.84 ms | 447.49 ms | 75.65 ms |
| 55aaf9b | 341.96 ms | 399.96 ms | 58.00 ms |
| 9139b91 | 351.35 ms | 355.63 ms | 4.28 ms |
| ee747ae | 554.98 ms | 611.50 ms | 56.52 ms |
| 674d437 | 355.28 ms | 504.18 ms | 148.90 ms |
| f064536 | 329.00 ms | 395.62 ms | 66.62 ms |
| ee747ae | 415.92 ms | 470.15 ms | 54.23 ms |
| 1df7eb6 | 397.04 ms | 429.64 ms | 32.60 ms |
| d217708 | 355.34 ms | 381.39 ms | 26.05 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| abfcc92 | 1.58 MiB | 2.13 MiB | 557.31 KiB |
| b3d8889 | 1.58 MiB | 2.10 MiB | 535.07 KiB |
| 55aaf9b | 0 B | 0 B | 0 B |
| 9139b91 | 1.58 MiB | 2.13 MiB | 559.52 KiB |
| ee747ae | 1.58 MiB | 2.10 MiB | 530.95 KiB |
| 674d437 | 1.58 MiB | 2.10 MiB | 530.94 KiB |
| f064536 | 1.58 MiB | 2.20 MiB | 633.90 KiB |
| ee747ae | 1.58 MiB | 2.10 MiB | 530.95 KiB |
| 1df7eb6 | 1.58 MiB | 2.10 MiB | 532.97 KiB |
| d217708 | 1.58 MiB | 2.10 MiB | 532.97 KiB |
Previous results on branch: feat/strict-trace-continuation
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 79a9407 | 348.85 ms | 428.10 ms | 79.25 ms |
| 455f13a | 320.20 ms | 367.52 ms | 47.33 ms |
| f4b6f75 | 392.12 ms | 440.69 ms | 48.57 ms |
| bbab8da | 309.58 ms | 363.22 ms | 53.64 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 79a9407 | 1.58 MiB | 2.29 MiB | 723.70 KiB |
| 455f13a | 0 B | 0 B | 0 B |
| f4b6f75 | 0 B | 0 B | 0 B |
| bbab8da | 1.58 MiB | 2.29 MiB | 723.51 KiB |
Extract org ID from DSN host, add strictTraceContinuation and orgId options, propagate sentry-org_id in baggage, and validate incoming traces per the decision matrix. Closes #5128
Add public API declarations for new org ID and strict trace continuation methods on Baggage, PropagationContext, and SentryOptions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make Dsn.orgId final, remove unnecessary setter - Fix test signatures to use List<String> for baggage headers - Add strictTraceContinuation and orgId to ExternalOptions and merge() - Add options to ManifestMetadataReader for Android manifest config - Use Sentry.getCurrentScopes().getOptions() in legacy fromHeaders overload - Improve CHANGELOG description with details about new options - Update API surface file for ExternalOptions changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comment to empty catch block in PropagationContext to satisfy -Werror - Add setOrgId setter to Dsn class (remove final modifier on orgId field) to support the existing test for org ID override Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
457e177 to
e30064c
Compare
…x OTel overload, add option tests, make Dsn.orgId final - Remove PropagationContext.fromHeaders overload without SentryOptions; all callers now pass options (or null) explicitly instead of relying on Sentry.getCurrentScopes() - Add SentryOptions parameter to the OTel-facing fromHeaders(SentryTraceHeader, Baggage, SpanId) overload so OpenTelemetry integrations also check orgId - Make Dsn.orgId final and remove the setter — orgId is only set during DSN parsing in the constructor - Add tests for strictTraceContinuation and orgId options in ExternalOptionsTest, SentryOptionsTest, and ManifestMetadataReaderTest - Improve CHANGELOG entry with customer-facing description - Update API declarations (apiDump) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sentry Build Distribution
|
adinauer
left a comment
There was a problem hiding this comment.
Please also change SentryAutoConfigurationTest.kt in all 3 spring boot modules.
I assume it's OK to not backfill org ID on a frozen baggage (i.e. incoming baggage without org ID).
...try/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java
Outdated
Show resolved
Hide resolved
- Remove duplicated org ID check in PropagationContext.fromHeaders, pass options through to the single-check overload instead - Add debug log when trace is not continued in the SentryTraceHeader overload - Handle empty/blank org ID strings in shouldContinueTrace to avoid silently breaking traces - Update OtelSentrySpanProcessor to use PropagationContext.fromHeaders with options for org_id validation - Rename ExternalOptions property key to enable-strict-trace-continuation (matching the enable- prefix convention for newer options) - Update ExternalOptionsTest to use the new property key - Add strict-trace-continuation and org-id properties to all 3 Spring Boot SentryAutoConfigurationTest modules - Improve CHANGELOG entry with detailed customer-facing descriptions and configuration examples for all options Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sentry Build Distribution
|
Update the trace-continuation rejection log message to cover all strict org ID validation failures, including missing org IDs, not just mismatches. Co-Authored-By: Claude <noreply@anthropic.com>
Rename the Android manifest option to io.sentry.strict-trace-continuation.enabled to align with existing enabled-style manifest flags. Update changelog documentation to match the new Android key. Co-Authored-By: Claude <noreply@anthropic.com>
Annotate SentryOptions.getEffectiveOrgId with ApiStatus.Internal since it is used as an internal helper for trace propagation org ID resolution. Co-Authored-By: Claude <noreply@anthropic.com>
Move strict trace continuation org-id validation logic to TracingUtils so it can be reused by tracing entry points. Update PropagationContext to call the shared helper and add dedicated TracingUtils tests for strict/non-strict org-id continuation outcomes. Co-Authored-By: Claude <noreply@anthropic.com>
Apply strict trace continuation checks in all OpenTelemetry propagator extract paths before creating remote parent span context. When org-id validation fails, return the original context and ignore incoming sentry-trace and baggage to keep propagation behavior aligned with strict continuation requirements. Add rejection tests for OtelSentryPropagator, deprecated SentryPropagator, and OpenTelemetryOtlpPropagator. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Empty/blank
orgIdbypasses DSN fallback silentlygetEffectiveOrgId()now treats empty or whitespace-only configured org IDs as unset so DSN org ID fallback is used, and a unit test was added to cover empty/blank inputs.
Or push these changes by commenting:
@cursor push 1b0f711f6d
Preview (1b0f711f6d)
diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java
--- a/sentry/src/main/java/io/sentry/SentryOptions.java
+++ b/sentry/src/main/java/io/sentry/SentryOptions.java
@@ -2337,7 +2337,7 @@
*/
@ApiStatus.Internal
public @Nullable String getEffectiveOrgId() {
- if (orgId != null) {
+ if (orgId != null && !orgId.trim().isEmpty()) {
return orgId;
}
try {
diff --git a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt
--- a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt
+++ b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt
@@ -1020,6 +1020,19 @@
}
@Test
+ fun `getEffectiveOrgId falls back to DSN org id when explicit orgId is empty or blank`() {
+ val emptyOrgIdOptions = SentryOptions()
+ emptyOrgIdOptions.dsn = "https://key@o123.ingest.sentry.io/456"
+ emptyOrgIdOptions.orgId = ""
+ assertEquals("123", emptyOrgIdOptions.effectiveOrgId)
+
+ val blankOrgIdOptions = SentryOptions()
+ blankOrgIdOptions.dsn = "https://key@o123.ingest.sentry.io/456"
+ blankOrgIdOptions.orgId = " "
+ assertEquals("123", blankOrgIdOptions.effectiveOrgId)
+ }
+
+ @Test
fun `getEffectiveOrgId falls back to DSN org id`() {
val options = SentryOptions()
options.dsn = "https://key@o123.ingest.sentry.io/456"This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
The getEffectiveOrgId() method only checked orgId != null, allowing empty strings and whitespace-only values to bypass the DSN fallback mechanism. This caused empty org IDs to propagate to outgoing baggage headers as sentry-org_id=, silently breaking trace continuation in strict mode. Update getEffectiveOrgId() to trim the orgId value and check if it's empty after trimming. Empty or blank values now correctly fall back to the DSN org ID instead of propagating as empty strings. Add comprehensive test coverage for all edge cases including empty strings, whitespace-only values, and their impact on baggage propagation and strict trace continuation. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| final @NotNull SentryOptions options, final @Nullable Baggage baggage) { | ||
| final @Nullable String rawSdkOrgId = options.getEffectiveOrgId(); | ||
| final @Nullable String sdkOrgId = | ||
| (rawSdkOrgId != null && !rawSdkOrgId.trim().isEmpty()) ? rawSdkOrgId.trim() : null; |
There was a problem hiding this comment.
Redundant trim of already-trimmed effective org ID
Low Severity
shouldContinueTrace re-trims and re-checks getEffectiveOrgId() for emptiness, but getEffectiveOrgId() already guarantees it returns either null or a trimmed, non-empty string. The defensive wrapping of rawSdkOrgId into sdkOrgId is wholly redundant — it can never produce a different result from simply using rawSdkOrgId directly.



Summary
o123.ingest.sentry.io→"123")strictTraceContinuation(boolean, default false) andorgId(String) options toSentryOptionssentry-org_idin baggage / Dynamic Sampling ContextDecision Matrix
Changes
Dsn.java— org ID extraction from host using^o(\d+)\.regexSentryOptions.java—strictTraceContinuation,orgId, andgetEffectiveOrgId()Baggage.java—ORG_IDDSCKey, getter/setter, population insetValuesFromTransaction/setValuesFromScope/fromEventPropagationContext.java—shouldContinueTrace()logic infromHeaders()Scopes.java— pass options tofromHeaders()Test plan
Closes #5128
🤖 Generated with Claude Code