Skip to content

Commit 108eb2d

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 1cfc2ea commit 108eb2d

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
@@ -10,6 +10,10 @@
1010
- Support collections and arrays in attribute type inference ([#5124](https://github.com/getsentry/sentry-java/pull/5124))
1111
- Add support for `SENTRY_SAMPLE_RATE` environment variable / `sample-rate` property ([#5112](https://github.com/getsentry/sentry-java/pull/5112))
1212
- Add strict trace continuation support ([#5136](https://github.com/getsentry/sentry-java/pull/5136))
13+
- The SDK now extracts `org_id` from the DSN host and propagates it via `sentry-org_id` in the baggage header.
14+
- When an incoming trace has a mismatched `org_id`, the SDK starts a new trace instead of continuing the foreign one.
15+
- 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.
16+
- New option `orgId`: allows explicitly setting the organization ID for self-hosted and Relay setups where it cannot be extracted from the DSN.
1317
- 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))
1418
- OpenTelemetry is configured to send spans to Sentry directly using an OTLP endpoint.
1519
- 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
@@ -167,6 +167,9 @@ final class ManifestMetadataReader {
167167

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

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

172175
static final String SPOTLIGHT_CONNECTION_URL = "io.sentry.spotlight.url";
@@ -658,6 +661,18 @@ static void applyMetadata(
658661
feedbackOptions.setShowBranding(
659662
readBool(metadata, logger, FEEDBACK_SHOW_BRANDING, feedbackOptions.isShowBranding()));
660663

664+
options.setStrictTraceContinuation(
665+
readBool(
666+
metadata,
667+
logger,
668+
STRICT_TRACE_CONTINUATION,
669+
options.isStrictTraceContinuation()));
670+
671+
final @Nullable String orgId = readString(metadata, logger, ORG_ID, null);
672+
if (orgId != null) {
673+
options.setOrgId(orgId);
674+
}
675+
661676
options.setEnableSpotlight(
662677
readBool(metadata, logger, SPOTLIGHT_ENABLE, options.isEnableSpotlight()));
663678

sentry/api/sentry.api

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ public final class io/sentry/ExternalOptions {
504504
public fun getInAppExcludes ()Ljava/util/List;
505505
public fun getInAppIncludes ()Ljava/util/List;
506506
public fun getMaxRequestBodySize ()Lio/sentry/SentryOptions$RequestSize;
507+
public fun getOrgId ()Ljava/lang/String;
507508
public fun getPrintUncaughtStackTrace ()Ljava/lang/Boolean;
508509
public fun getProfileLifecycle ()Lio/sentry/ProfileLifecycle;
509510
public fun getProfileSessionSampleRate ()Ljava/lang/Double;
@@ -531,6 +532,7 @@ public final class io/sentry/ExternalOptions {
531532
public fun isGlobalHubMode ()Ljava/lang/Boolean;
532533
public fun isSendDefaultPii ()Ljava/lang/Boolean;
533534
public fun isSendModules ()Ljava/lang/Boolean;
535+
public fun isStrictTraceContinuation ()Ljava/lang/Boolean;
534536
public fun setCaptureOpenTelemetryEvents (Ljava/lang/Boolean;)V
535537
public fun setCron (Lio/sentry/SentryOptions$Cron;)V
536538
public fun setDebug (Ljava/lang/Boolean;)V
@@ -553,6 +555,7 @@ public final class io/sentry/ExternalOptions {
553555
public fun setIgnoredErrors (Ljava/util/List;)V
554556
public fun setIgnoredTransactions (Ljava/util/List;)V
555557
public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V
558+
public fun setOrgId (Ljava/lang/String;)V
556559
public fun setPrintUncaughtStackTrace (Ljava/lang/Boolean;)V
557560
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
558561
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
@@ -567,6 +570,7 @@ public final class io/sentry/ExternalOptions {
567570
public fun setSendModules (Ljava/lang/Boolean;)V
568571
public fun setServerName (Ljava/lang/String;)V
569572
public fun setSpotlightConnectionUrl (Ljava/lang/String;)V
573+
public fun setStrictTraceContinuation (Ljava/lang/Boolean;)V
570574
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
571575
public fun setTracesSampleRate (Ljava/lang/Double;)V
572576
}

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.
@@ -94,13 +94,15 @@ URI getSentryUri() {
9494
scheme, null, uri.getHost(), uri.getPort(), path + "api/" + projectId, null, null);
9595

9696
// Extract org ID from host (e.g., "o123.ingest.sentry.io" -> "123")
97+
String extractedOrgId = null;
9798
final String host = uri.getHost();
9899
if (host != null) {
99100
final Matcher matcher = ORG_ID_PATTERN.matcher(host);
100101
if (matcher.find()) {
101-
orgId = matcher.group(1);
102+
extractedOrgId = matcher.group(1);
102103
}
103104
}
105+
orgId = extractedOrgId;
104106
} catch (Throwable e) {
105107
throw new IllegalArgumentException(e);
106108
}
@@ -109,8 +111,4 @@ URI getSentryUri() {
109111
public @Nullable String getOrgId() {
110112
return orgId;
111113
}
112-
113-
void setOrgId(final @Nullable String orgId) {
114-
this.orgId = orgId;
115-
}
116114
}

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

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

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

6871
@SuppressWarnings("unchecked")
@@ -213,6 +216,10 @@ public final class ExternalOptions {
213216
options.setCron(cron);
214217
}
215218

219+
options.setStrictTraceContinuation(
220+
propertiesProvider.getBooleanProperty("strict-trace-continuation"));
221+
options.setOrgId(propertiesProvider.getProperty("org-id"));
222+
216223
options.setEnableSpotlight(propertiesProvider.getBooleanProperty("enable-spotlight"));
217224
options.setSpotlightConnectionUrl(propertiesProvider.getProperty("spotlight-connection-url"));
218225
options.setProfileSessionSampleRate(
@@ -589,6 +596,22 @@ public void setProfilingTracesDirPath(@Nullable String profilingTracesDirPath) {
589596
this.profilingTracesDirPath = profilingTracesDirPath;
590597
}
591598

599+
public @Nullable Boolean isStrictTraceContinuation() {
600+
return strictTraceContinuation;
601+
}
602+
603+
public void setStrictTraceContinuation(final @Nullable Boolean strictTraceContinuation) {
604+
this.strictTraceContinuation = strictTraceContinuation;
605+
}
606+
607+
public @Nullable String getOrgId() {
608+
return orgId;
609+
}
610+
611+
public void setOrgId(final @Nullable String orgId) {
612+
this.orgId = orgId;
613+
}
614+
592615
public @Nullable ProfileLifecycle getProfileLifecycle() {
593616
return profileLifecycle;
594617
}

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
@@ -3571,6 +3571,12 @@ public void merge(final @NotNull ExternalOptions options) {
35713571
if (options.getProfileLifecycle() != null) {
35723572
setProfileLifecycle(options.getProfileLifecycle());
35733573
}
3574+
if (options.isStrictTraceContinuation() != null) {
3575+
setStrictTraceContinuation(options.isStrictTraceContinuation());
3576+
}
3577+
if (options.getOrgId() != null) {
3578+
setOrgId(options.getOrgId());
3579+
}
35743580
}
35753581

35763582
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)