Skip to content

Commit 457e177

Browse files
giortzisgclaude
andcommitted
Address review comments for strict trace continuation
- 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>
1 parent 96a5ff2 commit 457e177

File tree

8 files changed

+72
-17
lines changed

8 files changed

+72
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
### Features
66

77
- Add strict trace continuation support ([#5136](https://github.com/getsentry/sentry-java/pull/5136))
8+
- The SDK now extracts `org_id` from the DSN host and propagates it via `sentry-org_id` in the baggage header.
9+
- When an incoming trace has a mismatched `org_id`, the SDK starts a new trace instead of continuing the foreign one.
10+
- New option `strictTraceContinuation` (default `false`): when enabled, both the SDK's org ID and the incoming baggage org ID must be present and match for a trace to be continued.
11+
- New option `orgId`: allows explicitly setting the organization ID for self-hosted and Relay setups where it cannot be extracted from the DSN.
812
- Create `sentry-opentelemetry-otlp` and `sentry-opentelemetry-otlp-spring` modules for combining OpenTelemetry SDK OTLP export with Sentry SDK ([#5100](https://github.com/getsentry/sentry-java/pull/5100))
913
- OpenTelemetry is configured to send spans to Sentry directly using an OTLP endpoint.
1014
- Sentry only uses trace and span ID from OpenTelemetry (via `OpenTelemetryOtlpEventProcessor`) but will not send spans through OpenTelemetry nor use OpenTelemetry `Context` for `Scopes` propagation.

sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ final class ManifestMetadataReader {
166166

167167
static final String FEEDBACK_SHOW_BRANDING = "io.sentry.feedback.show-branding";
168168

169+
static final String STRICT_TRACE_CONTINUATION = "io.sentry.strict-trace-continuation";
170+
static final String ORG_ID = "io.sentry.org-id";
171+
169172
static final String SPOTLIGHT_ENABLE = "io.sentry.spotlight.enable";
170173

171174
static final String SPOTLIGHT_CONNECTION_URL = "io.sentry.spotlight.url";
@@ -655,6 +658,18 @@ static void applyMetadata(
655658
feedbackOptions.setShowBranding(
656659
readBool(metadata, logger, FEEDBACK_SHOW_BRANDING, feedbackOptions.isShowBranding()));
657660

661+
options.setStrictTraceContinuation(
662+
readBool(
663+
metadata,
664+
logger,
665+
STRICT_TRACE_CONTINUATION,
666+
options.isStrictTraceContinuation()));
667+
668+
final @Nullable String orgId = readString(metadata, logger, ORG_ID, null);
669+
if (orgId != null) {
670+
options.setOrgId(orgId);
671+
}
672+
658673
options.setEnableSpotlight(
659674
readBool(metadata, logger, SPOTLIGHT_ENABLE, options.isEnableSpotlight()));
660675

sentry/api/sentry.api

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ public final class io/sentry/ExternalOptions {
499499
public fun getInAppExcludes ()Ljava/util/List;
500500
public fun getInAppIncludes ()Ljava/util/List;
501501
public fun getMaxRequestBodySize ()Lio/sentry/SentryOptions$RequestSize;
502+
public fun getOrgId ()Ljava/lang/String;
502503
public fun getPrintUncaughtStackTrace ()Ljava/lang/Boolean;
503504
public fun getProfileLifecycle ()Lio/sentry/ProfileLifecycle;
504505
public fun getProfileSessionSampleRate ()Ljava/lang/Double;
@@ -525,6 +526,7 @@ public final class io/sentry/ExternalOptions {
525526
public fun isGlobalHubMode ()Ljava/lang/Boolean;
526527
public fun isSendDefaultPii ()Ljava/lang/Boolean;
527528
public fun isSendModules ()Ljava/lang/Boolean;
529+
public fun isStrictTraceContinuation ()Ljava/lang/Boolean;
528530
public fun setCaptureOpenTelemetryEvents (Ljava/lang/Boolean;)V
529531
public fun setCron (Lio/sentry/SentryOptions$Cron;)V
530532
public fun setDebug (Ljava/lang/Boolean;)V
@@ -547,6 +549,7 @@ public final class io/sentry/ExternalOptions {
547549
public fun setIgnoredErrors (Ljava/util/List;)V
548550
public fun setIgnoredTransactions (Ljava/util/List;)V
549551
public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V
552+
public fun setOrgId (Ljava/lang/String;)V
550553
public fun setPrintUncaughtStackTrace (Ljava/lang/Boolean;)V
551554
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
552555
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
@@ -560,6 +563,7 @@ public final class io/sentry/ExternalOptions {
560563
public fun setSendModules (Ljava/lang/Boolean;)V
561564
public fun setServerName (Ljava/lang/String;)V
562565
public fun setSpotlightConnectionUrl (Ljava/lang/String;)V
566+
public fun setStrictTraceContinuation (Ljava/lang/Boolean;)V
563567
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
564568
public fun setTracesSampleRate (Ljava/lang/Double;)V
565569
}

sentry/src/main/java/io/sentry/Dsn.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ final class Dsn {
1515
private final @Nullable String secretKey;
1616
private final @NotNull String publicKey;
1717
private final @NotNull URI sentryUri;
18-
private @Nullable String orgId;
18+
private final @Nullable String orgId;
1919

2020
/*
2121
/ The project ID which the authenticated user is bound to.
@@ -91,13 +91,15 @@ URI getSentryUri() {
9191
scheme, null, uri.getHost(), uri.getPort(), path + "api/" + projectId, null, null);
9292

9393
// Extract org ID from host (e.g., "o123.ingest.sentry.io" -> "123")
94+
String extractedOrgId = null;
9495
final String host = uri.getHost();
9596
if (host != null) {
9697
final Matcher matcher = ORG_ID_PATTERN.matcher(host);
9798
if (matcher.find()) {
98-
orgId = matcher.group(1);
99+
extractedOrgId = matcher.group(1);
99100
}
100101
}
102+
orgId = extractedOrgId;
101103
} catch (Throwable e) {
102104
throw new IllegalArgumentException(e);
103105
}
@@ -106,8 +108,4 @@ URI getSentryUri() {
106108
public @Nullable String getOrgId() {
107109
return orgId;
108110
}
109-
110-
void setOrgId(final @Nullable String orgId) {
111-
this.orgId = orgId;
112-
}
113111
}

sentry/src/main/java/io/sentry/ExternalOptions.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ public final class ExternalOptions {
6262
private @Nullable String profilingTracesDirPath;
6363
private @Nullable ProfileLifecycle profileLifecycle;
6464

65+
private @Nullable Boolean strictTraceContinuation;
66+
private @Nullable String orgId;
67+
6568
private @Nullable SentryOptions.Cron cron;
6669

6770
@SuppressWarnings("unchecked")
@@ -211,6 +214,10 @@ public final class ExternalOptions {
211214
options.setCron(cron);
212215
}
213216

217+
options.setStrictTraceContinuation(
218+
propertiesProvider.getBooleanProperty("strict-trace-continuation"));
219+
options.setOrgId(propertiesProvider.getProperty("org-id"));
220+
214221
options.setEnableSpotlight(propertiesProvider.getBooleanProperty("enable-spotlight"));
215222
options.setSpotlightConnectionUrl(propertiesProvider.getProperty("spotlight-connection-url"));
216223
options.setProfileSessionSampleRate(
@@ -579,6 +586,22 @@ public void setProfilingTracesDirPath(@Nullable String profilingTracesDirPath) {
579586
this.profilingTracesDirPath = profilingTracesDirPath;
580587
}
581588

589+
public @Nullable Boolean isStrictTraceContinuation() {
590+
return strictTraceContinuation;
591+
}
592+
593+
public void setStrictTraceContinuation(final @Nullable Boolean strictTraceContinuation) {
594+
this.strictTraceContinuation = strictTraceContinuation;
595+
}
596+
597+
public @Nullable String getOrgId() {
598+
return orgId;
599+
}
600+
601+
public void setOrgId(final @Nullable String orgId) {
602+
this.orgId = orgId;
603+
}
604+
582605
public @Nullable ProfileLifecycle getProfileLifecycle() {
583606
return profileLifecycle;
584607
}

sentry/src/main/java/io/sentry/PropagationContext.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ public static PropagationContext fromHeaders(
2323
final @NotNull ILogger logger,
2424
final @Nullable String sentryTraceHeaderString,
2525
final @Nullable List<String> baggageHeaderStrings) {
26-
return fromHeaders(logger, sentryTraceHeaderString, baggageHeaderStrings, null);
26+
@Nullable SentryOptions options = null;
27+
try {
28+
options = Sentry.getCurrentScopes().getOptions();
29+
} catch (Throwable ignored) {
30+
}
31+
return fromHeaders(logger, sentryTraceHeaderString, baggageHeaderStrings, options);
2732
}
2833

2934
public static @NotNull PropagationContext fromHeaders(

sentry/src/main/java/io/sentry/SentryOptions.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,12 @@ public void merge(final @NotNull ExternalOptions options) {
35843584
if (options.getProfileLifecycle() != null) {
35853585
setProfileLifecycle(options.getProfileLifecycle());
35863586
}
3587+
if (options.isStrictTraceContinuation() != null) {
3588+
setStrictTraceContinuation(options.isStrictTraceContinuation());
3589+
}
3590+
if (options.getOrgId() != null) {
3591+
setOrgId(options.getOrgId());
3592+
}
35873593
}
35883594

35893595
private @NotNull SdkVersion createSdkVersion() {

sentry/src/test/java/io/sentry/PropagationContextTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class PropagationContextTest {
8181
PropagationContext.fromHeaders(
8282
NoOpLogger.getInstance(),
8383
sentryTrace,
84-
makeBaggage("1"),
84+
listOf(makeBaggage("1")),
8585
options,
8686
)
8787
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -94,7 +94,7 @@ class PropagationContextTest {
9494
PropagationContext.fromHeaders(
9595
NoOpLogger.getInstance(),
9696
sentryTrace,
97-
makeBaggage(null),
97+
listOf(makeBaggage(null)),
9898
options,
9999
)
100100
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -107,7 +107,7 @@ class PropagationContextTest {
107107
PropagationContext.fromHeaders(
108108
NoOpLogger.getInstance(),
109109
sentryTrace,
110-
makeBaggage("1"),
110+
listOf(makeBaggage("1")),
111111
options,
112112
)
113113
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -120,7 +120,7 @@ class PropagationContextTest {
120120
PropagationContext.fromHeaders(
121121
NoOpLogger.getInstance(),
122122
sentryTrace,
123-
makeBaggage(null),
123+
listOf(makeBaggage(null)),
124124
options,
125125
)
126126
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -133,7 +133,7 @@ class PropagationContextTest {
133133
PropagationContext.fromHeaders(
134134
NoOpLogger.getInstance(),
135135
sentryTrace,
136-
makeBaggage("1"),
136+
listOf(makeBaggage("1")),
137137
options,
138138
)
139139
assertNotEquals(incomingTraceId, pc.traceId.toString())
@@ -146,7 +146,7 @@ class PropagationContextTest {
146146
PropagationContext.fromHeaders(
147147
NoOpLogger.getInstance(),
148148
sentryTrace,
149-
makeBaggage("1"),
149+
listOf(makeBaggage("1")),
150150
options,
151151
)
152152
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -159,7 +159,7 @@ class PropagationContextTest {
159159
PropagationContext.fromHeaders(
160160
NoOpLogger.getInstance(),
161161
sentryTrace,
162-
makeBaggage(null),
162+
listOf(makeBaggage(null)),
163163
options,
164164
)
165165
assertNotEquals(incomingTraceId, pc.traceId.toString())
@@ -172,7 +172,7 @@ class PropagationContextTest {
172172
PropagationContext.fromHeaders(
173173
NoOpLogger.getInstance(),
174174
sentryTrace,
175-
makeBaggage("1"),
175+
listOf(makeBaggage("1")),
176176
options,
177177
)
178178
assertNotEquals(incomingTraceId, pc.traceId.toString())
@@ -185,7 +185,7 @@ class PropagationContextTest {
185185
PropagationContext.fromHeaders(
186186
NoOpLogger.getInstance(),
187187
sentryTrace,
188-
makeBaggage(null),
188+
listOf(makeBaggage(null)),
189189
options,
190190
)
191191
assertEquals(incomingTraceId, pc.traceId.toString())
@@ -198,7 +198,7 @@ class PropagationContextTest {
198198
PropagationContext.fromHeaders(
199199
NoOpLogger.getInstance(),
200200
sentryTrace,
201-
makeBaggage("1"),
201+
listOf(makeBaggage("1")),
202202
options,
203203
)
204204
assertNotEquals(incomingTraceId, pc.traceId.toString())

0 commit comments

Comments
 (0)