Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
dc8d319
feat: Add strict trace continuation support
giortzisg Mar 2, 2026
e550ae3
Format code
getsentry-bot Mar 2, 2026
c272ee4
Add changelog entry
giortzisg Mar 2, 2026
1cfc2ea
Update API surface file for strict trace continuation
giortzisg Mar 3, 2026
108eb2d
Address review comments for strict trace continuation
giortzisg Mar 4, 2026
e30064c
Fix compilation errors after rebase on main
giortzisg Mar 4, 2026
4545735
fix: Move changelog entry to Unreleased section
giortzisg Mar 4, 2026
61ada6a
Format code
getsentry-bot Mar 4, 2026
519f6a6
fix: Address review comments — pass options to PropagationContext, fi…
giortzisg Mar 9, 2026
360fc94
fix: Add missing 8.34.1 changelog section
giortzisg Mar 9, 2026
ea9f456
merge: Resolve changelog conflict with main
giortzisg Mar 9, 2026
58bfc8e
Format code
getsentry-bot Mar 9, 2026
ebe8c4c
fix: Address PR review comments for strict trace continuation
giortzisg Mar 11, 2026
824b30b
Format code
getsentry-bot Mar 11, 2026
e2fdc46
fix(tracing): Clarify strict org validation debug log
adinauer Mar 20, 2026
d3b073d
fix(android): Use enabled suffix for strict trace manifest key
adinauer Mar 20, 2026
f7fef22
fix(api): Mark effective org ID helper as internal
adinauer Mar 20, 2026
71562fa
ref(tracing): Extract trace continuation decision into TracingUtils
adinauer Mar 23, 2026
327d897
fix(opentelemetry): Enforce strict continuation in propagators
adinauer Mar 23, 2026
f1edc98
Merge branch 'main' into feat/strict-trace-continuation
adinauer Mar 23, 2026
863f05b
Format code
getsentry-bot Mar 23, 2026
1d8e301
fix(tracing): Fix empty orgId bypassing DSN fallback
adinauer Mar 26, 2026
25e71db
Merge branch 'main' into feat/strict-trace-continuation
adinauer Mar 26, 2026
a3c86e7
Format code
getsentry-bot Mar 26, 2026
3d1d119
ref: Remove redundant trim of already-trimmed effective org ID
adinauer Mar 27, 2026
bad469f
Merge branch 'main' into feat/strict-trace-continuation
adinauer Mar 30, 2026
cf7d9fe
ref(tracing): Revert shouldContinueTrace check in OtelSentrySpanProce…
adinauer Mar 30, 2026
435d2e7
fix(test): Clean up global Sentry state in SentryPropagatorTest
adinauer Mar 30, 2026
63222e5
fix(test): Use mock scopes in propagator strict continuation tests
adinauer Mar 30, 2026
a4cd81a
fix(test): Reset OTel context in propagator test teardown
adinauer Mar 30, 2026
f029100
Merge branch 'main' into feat/strict-trace-continuation
adinauer Mar 30, 2026
070ee32
fix(test): Add back test for inject with invalid span
adinauer Mar 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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>
  • Loading branch information
giortzisg and claude committed Mar 4, 2026
commit 108eb2d068c6afddccc5b20a2178267bfa664f31
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
- Support collections and arrays in attribute type inference ([#5124](https://github.com/getsentry/sentry-java/pull/5124))
- Add support for `SENTRY_SAMPLE_RATE` environment variable / `sample-rate` property ([#5112](https://github.com/getsentry/sentry-java/pull/5112))
- Add strict trace continuation support ([#5136](https://github.com/getsentry/sentry-java/pull/5136))
Comment thread
adinauer marked this conversation as resolved.
Outdated
- The SDK now extracts `org_id` from the DSN host and propagates it via `sentry-org_id` in the baggage header.
- When an incoming trace has a mismatched `org_id`, the SDK starts a new trace instead of continuing the foreign one.
- 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.
- New option `orgId`: allows explicitly setting the organization ID for self-hosted and Relay setups where it cannot be extracted from the DSN.
- 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))
- OpenTelemetry is configured to send spans to Sentry directly using an OTLP endpoint.
- 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ final class ManifestMetadataReader {

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

static final String STRICT_TRACE_CONTINUATION = "io.sentry.strict-trace-continuation";
static final String ORG_ID = "io.sentry.org-id";

static final String SPOTLIGHT_ENABLE = "io.sentry.spotlight.enable";

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

options.setStrictTraceContinuation(
readBool(
metadata,
logger,
STRICT_TRACE_CONTINUATION,
options.isStrictTraceContinuation()));

final @Nullable String orgId = readString(metadata, logger, ORG_ID, null);
if (orgId != null) {
options.setOrgId(orgId);
}

options.setEnableSpotlight(
readBool(metadata, logger, SPOTLIGHT_ENABLE, options.isEnableSpotlight()));

Expand Down
4 changes: 4 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ public final class io/sentry/ExternalOptions {
public fun getInAppExcludes ()Ljava/util/List;
public fun getInAppIncludes ()Ljava/util/List;
public fun getMaxRequestBodySize ()Lio/sentry/SentryOptions$RequestSize;
public fun getOrgId ()Ljava/lang/String;
public fun getPrintUncaughtStackTrace ()Ljava/lang/Boolean;
public fun getProfileLifecycle ()Lio/sentry/ProfileLifecycle;
public fun getProfileSessionSampleRate ()Ljava/lang/Double;
Expand Down Expand Up @@ -531,6 +532,7 @@ public final class io/sentry/ExternalOptions {
public fun isGlobalHubMode ()Ljava/lang/Boolean;
public fun isSendDefaultPii ()Ljava/lang/Boolean;
public fun isSendModules ()Ljava/lang/Boolean;
public fun isStrictTraceContinuation ()Ljava/lang/Boolean;
public fun setCaptureOpenTelemetryEvents (Ljava/lang/Boolean;)V
public fun setCron (Lio/sentry/SentryOptions$Cron;)V
public fun setDebug (Ljava/lang/Boolean;)V
Expand All @@ -553,6 +555,7 @@ public final class io/sentry/ExternalOptions {
public fun setIgnoredErrors (Ljava/util/List;)V
public fun setIgnoredTransactions (Ljava/util/List;)V
public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V
public fun setOrgId (Ljava/lang/String;)V
public fun setPrintUncaughtStackTrace (Ljava/lang/Boolean;)V
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
Expand All @@ -567,6 +570,7 @@ public final class io/sentry/ExternalOptions {
public fun setSendModules (Ljava/lang/Boolean;)V
public fun setServerName (Ljava/lang/String;)V
public fun setSpotlightConnectionUrl (Ljava/lang/String;)V
public fun setStrictTraceContinuation (Ljava/lang/Boolean;)V
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
public fun setTracesSampleRate (Ljava/lang/Double;)V
}
Expand Down
10 changes: 4 additions & 6 deletions sentry/src/main/java/io/sentry/Dsn.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class Dsn {
private final @Nullable String secretKey;
private final @NotNull String publicKey;
private final @NotNull URI sentryUri;
private @Nullable String orgId;
private final @Nullable String orgId;

/*
/ The project ID which the authenticated user is bound to.
Expand Down Expand Up @@ -94,13 +94,15 @@ URI getSentryUri() {
scheme, null, uri.getHost(), uri.getPort(), path + "api/" + projectId, null, null);

// Extract org ID from host (e.g., "o123.ingest.sentry.io" -> "123")
String extractedOrgId = null;
final String host = uri.getHost();
if (host != null) {
final Matcher matcher = ORG_ID_PATTERN.matcher(host);
if (matcher.find()) {
orgId = matcher.group(1);
extractedOrgId = matcher.group(1);
}
}
orgId = extractedOrgId;
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
Expand All @@ -109,8 +111,4 @@ URI getSentryUri() {
public @Nullable String getOrgId() {
return orgId;
}

void setOrgId(final @Nullable String orgId) {
this.orgId = orgId;
}
}
23 changes: 23 additions & 0 deletions sentry/src/main/java/io/sentry/ExternalOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public final class ExternalOptions {
private @Nullable String profilingTracesDirPath;
private @Nullable ProfileLifecycle profileLifecycle;

private @Nullable Boolean strictTraceContinuation;
private @Nullable String orgId;

private @Nullable SentryOptions.Cron cron;

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -213,6 +216,10 @@ public final class ExternalOptions {
options.setCron(cron);
}

options.setStrictTraceContinuation(
propertiesProvider.getBooleanProperty("strict-trace-continuation"));
Comment thread
adinauer marked this conversation as resolved.
Outdated
options.setOrgId(propertiesProvider.getProperty("org-id"));

options.setEnableSpotlight(propertiesProvider.getBooleanProperty("enable-spotlight"));
options.setSpotlightConnectionUrl(propertiesProvider.getProperty("spotlight-connection-url"));
options.setProfileSessionSampleRate(
Expand Down Expand Up @@ -589,6 +596,22 @@ public void setProfilingTracesDirPath(@Nullable String profilingTracesDirPath) {
this.profilingTracesDirPath = profilingTracesDirPath;
}

public @Nullable Boolean isStrictTraceContinuation() {
return strictTraceContinuation;
}

public void setStrictTraceContinuation(final @Nullable Boolean strictTraceContinuation) {
this.strictTraceContinuation = strictTraceContinuation;
}

public @Nullable String getOrgId() {
return orgId;
}

public void setOrgId(final @Nullable String orgId) {
this.orgId = orgId;
}

public @Nullable ProfileLifecycle getProfileLifecycle() {
return profileLifecycle;
}
Expand Down
7 changes: 6 additions & 1 deletion sentry/src/main/java/io/sentry/PropagationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ public static PropagationContext fromHeaders(
final @NotNull ILogger logger,
final @Nullable String sentryTraceHeaderString,
final @Nullable List<String> baggageHeaderStrings) {
return fromHeaders(logger, sentryTraceHeaderString, baggageHeaderStrings, null);
@Nullable SentryOptions options = null;
try {
options = Sentry.getCurrentScopes().getOptions();
} catch (Throwable ignored) {
}
return fromHeaders(logger, sentryTraceHeaderString, baggageHeaderStrings, options);
}

public static @NotNull PropagationContext fromHeaders(
Expand Down
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3571,6 +3571,12 @@ public void merge(final @NotNull ExternalOptions options) {
if (options.getProfileLifecycle() != null) {
setProfileLifecycle(options.getProfileLifecycle());
}
if (options.isStrictTraceContinuation() != null) {
setStrictTraceContinuation(options.isStrictTraceContinuation());
}
if (options.getOrgId() != null) {
setOrgId(options.getOrgId());
}
Comment thread
adinauer marked this conversation as resolved.
}

private @NotNull SdkVersion createSdkVersion() {
Expand Down
20 changes: 10 additions & 10 deletions sentry/src/test/java/io/sentry/PropagationContextTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -94,7 +94,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage(null),
listOf(makeBaggage(null)),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -107,7 +107,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -120,7 +120,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage(null),
listOf(makeBaggage(null)),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -133,7 +133,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
Comment thread
adinauer marked this conversation as resolved.
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertNotEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -146,7 +146,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -159,7 +159,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage(null),
listOf(makeBaggage(null)),
options,
)
assertNotEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -172,7 +172,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertNotEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -185,7 +185,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage(null),
listOf(makeBaggage(null)),
options,
)
assertEquals(incomingTraceId, pc.traceId.toString())
Expand All @@ -198,7 +198,7 @@ class PropagationContextTest {
PropagationContext.fromHeaders(
NoOpLogger.getInstance(),
sentryTrace,
makeBaggage("1"),
listOf(makeBaggage("1")),
options,
)
assertNotEquals(incomingTraceId, pc.traceId.toString())
Expand Down