Skip to content

Commit 2fbb2e3

Browse files
authored
Fork isolation scope for root spans in OtelSentrySpanProcessor instead of OtelSentryPropagator (#4434)
* Fork isolation scope in SpanProcessor * improve creator strings * changelog * remove irrelevant tests
1 parent 4fc0c77 commit 2fbb2e3

4 files changed

Lines changed: 26 additions & 72 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
- `SentryAttribute.stringAttribute()` takes a `String` value
2222
- We opted for handling parameters via `SentryLogParameters` to avoid creating tons of overloads that are ambiguous.
2323

24+
### Fixes
25+
26+
- Isolation scope is now forked in `OtelSentrySpanProcessor` instead of `OtelSentryPropagator` ([#4434](https://github.com/getsentry/sentry-java/pull/4434))
27+
- Since propagator may never be invoked we moved the location where isolation scope is forked.
28+
- Not invoking `OtelSentryPropagator.extract` or having a `sentry-trace` header that failed to parse would cause isolation scope not to be forked.
29+
- This in turn caused data to bleed between scopes, e.g. from one request into another
30+
2431
### Dependencies
2532

2633
- Bump Spring Boot to `3.5.0` ([#4111](https://github.com/getsentry/sentry-java/pull/4111))

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentryPropagator.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.sentry.opentelemetry;
22

3-
import static io.sentry.opentelemetry.SentryOtelKeys.SENTRY_SCOPES_KEY;
4-
53
import io.opentelemetry.api.common.Attributes;
64
import io.opentelemetry.api.trace.Span;
75
import io.opentelemetry.api.trace.SpanContext;
@@ -15,7 +13,6 @@
1513
import io.sentry.BaggageHeader;
1614
import io.sentry.IScopes;
1715
import io.sentry.ScopesAdapter;
18-
import io.sentry.Sentry;
1916
import io.sentry.SentryLevel;
2017
import io.sentry.SentryOptions;
2118
import io.sentry.SentryTraceHeader;
@@ -105,16 +102,10 @@ public <C> void inject(final Context context, final C carrier, final TextMapSett
105102
@Override
106103
public <C> Context extract(
107104
final Context context, final C carrier, final TextMapGetter<C> getter) {
108-
final @Nullable IScopes scopesFromParentContext = context.get(SENTRY_SCOPES_KEY);
109-
final @NotNull IScopes scopesToUse =
110-
scopesFromParentContext != null
111-
? scopesFromParentContext.forkedScopes("propagator")
112-
: Sentry.forkedRootScopes("propagator");
113-
114105
final @Nullable String sentryTraceString =
115106
getter.get(carrier, SentryTraceHeader.SENTRY_TRACE_HEADER);
116107
if (sentryTraceString == null) {
117-
return context.with(SENTRY_SCOPES_KEY, scopesToUse);
108+
return context;
118109
}
119110

120111
try {
@@ -136,7 +127,6 @@ public <C> Context extract(
136127
final @NotNull Context modifiedContext =
137128
context
138129
.with(wrappedSpan)
139-
.with(SENTRY_SCOPES_KEY, scopesToUse)
140130
.with(SentryOtelKeys.SENTRY_TRACE_KEY, sentryTraceHeader)
141131
.with(SentryOtelKeys.SENTRY_BAGGAGE_KEY, baggage);
142132

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.opentelemetry.sdk.trace.SpanProcessor;
1111
import io.opentelemetry.sdk.trace.data.EventData;
1212
import io.opentelemetry.sdk.trace.data.ExceptionEventData;
13+
import io.opentelemetry.sdk.trace.data.SpanData;
1314
import io.sentry.Baggage;
1415
import io.sentry.DateUtils;
1516
import io.sentry.IScopes;
@@ -48,11 +49,7 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri
4849
return;
4950
}
5051

51-
final @Nullable IScopes scopesFromContext = parentContext.get(SENTRY_SCOPES_KEY);
52-
final @NotNull IScopes scopes =
53-
scopesFromContext != null
54-
? scopesFromContext.forkedCurrentScope("spanprocessor")
55-
: Sentry.forkedRootScopes("spanprocessor");
52+
final @NotNull IScopes scopes = forkScopes(parentContext, otelSpan.toSpanData());
5653

5754
final @Nullable IOtelSpanWrapper sentryParentSpan =
5855
spanStorage.getSentrySpan(otelSpan.getParentSpanContext());
@@ -111,6 +108,22 @@ public void onStart(final @NotNull Context parentContext, final @NotNull ReadWri
111108
spanStorage.storeSentrySpan(spanContext, sentrySpan);
112109
}
113110

111+
private IScopes forkScopes(final @NotNull Context context, final @NotNull SpanData span) {
112+
final @Nullable IScopes scopesFromContext = context.get(SENTRY_SCOPES_KEY);
113+
if (scopesFromContext == null) {
114+
return Sentry.forkedRootScopes("spanprocessor.new");
115+
}
116+
if (isRootSpan(span)) {
117+
return scopesFromContext.forkedScopes("spanprocessor.rootspan");
118+
}
119+
120+
return scopesFromContext.forkedCurrentScope("spanprocessor.nonrootspan");
121+
}
122+
123+
private boolean isRootSpan(SpanData otelSpan) {
124+
return !otelSpan.getParentSpanContext().isValid() || otelSpan.getParentSpanContext().isRemote();
125+
}
126+
114127
private @Nullable Boolean isSampled(
115128
final @NotNull ReadWriteSpan otelSpan,
116129
final @Nullable TracesSamplingDecision samplingDecision) {

sentry-opentelemetry/sentry-opentelemetry-core/src/test/kotlin/OtelSentryPropagatorTest.kt

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -47,62 +47,6 @@ class OtelSentryPropagatorTest {
4747
assertEquals(listOf("sentry-trace", "baggage"), propagator.fields())
4848
}
4949

50-
@Test
51-
fun `forks root scopes if none in context without headers`() {
52-
val propagator = OtelSentryPropagator()
53-
val carrier: Map<String, String> = mapOf()
54-
55-
val newContext = propagator.extract(Context.root(), carrier, MapGetter())
56-
57-
val scopes = newContext.get(SENTRY_SCOPES_KEY)
58-
assertNotNull(scopes)
59-
assertSame(Sentry.forkedRootScopes("test").parentScopes, scopes.parentScopes)
60-
}
61-
62-
@Test
63-
fun `forks scopes from context if present without headers`() {
64-
val propagator = OtelSentryPropagator()
65-
val carrier: Map<String, String> = mapOf()
66-
val scopeInContext = Sentry.forkedRootScopes("test")
67-
68-
val newContext = propagator.extract(Context.root().with(SENTRY_SCOPES_KEY, scopeInContext), carrier, MapGetter())
69-
70-
val scopes = newContext.get(SENTRY_SCOPES_KEY)
71-
assertNotNull(scopes)
72-
assertSame(scopeInContext, scopes.parentScopes)
73-
}
74-
75-
@Test
76-
fun `forks root scopes if none in context with headers`() {
77-
val propagator = OtelSentryPropagator()
78-
val carrier: Map<String, String> = mapOf(
79-
"sentry-trace" to "f9118105af4a2d42b4124532cd1065ff-424cffc8f94feeee-1",
80-
"baggage" to "sentry-environment=production,sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=df71f5972f754b4c85af13ff5c07017d"
81-
)
82-
83-
val newContext = propagator.extract(Context.root(), carrier, MapGetter())
84-
85-
val scopes = newContext.get(SENTRY_SCOPES_KEY)
86-
assertNotNull(scopes)
87-
assertSame(Sentry.forkedRootScopes("test").parentScopes, scopes.parentScopes)
88-
}
89-
90-
@Test
91-
fun `forks scopes from context if present with headers`() {
92-
val propagator = OtelSentryPropagator()
93-
val carrier: Map<String, String> = mapOf(
94-
"sentry-trace" to "f9118105af4a2d42b4124532cd1065ff-424cffc8f94feeee-1",
95-
"baggage" to "sentry-environment=production,sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=df71f5972f754b4c85af13ff5c07017d"
96-
)
97-
val scopeInContext = Sentry.forkedRootScopes("test")
98-
99-
val newContext = propagator.extract(Context.root().with(SENTRY_SCOPES_KEY, scopeInContext), carrier, MapGetter())
100-
101-
val scopes = newContext.get(SENTRY_SCOPES_KEY)
102-
assertNotNull(scopes)
103-
assertSame(scopeInContext, scopes.parentScopes)
104-
}
105-
10650
@Test
10751
fun `invalid sentry trace header returns context without modification`() {
10852
val propagator = OtelSentryPropagator()

0 commit comments

Comments
 (0)