Skip to content

Commit 6580ae6

Browse files
authored
Fix empty context activation behaviour (#3227)
1 parent c46b17b commit 6580ae6

File tree

8 files changed

+61
-75
lines changed

8 files changed

+61
-75
lines changed

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ActiveStack.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ class ActiveStack {
5858
*/
5959
private final Deque<ElasticContext<?>> activeContextStack = new ArrayDeque<ElasticContext<?>>();
6060

61-
ActiveStack(int stackMaxDepth) {
61+
private final EmptyElasticContext emptyContext;
62+
63+
ActiveStack(int stackMaxDepth, EmptyElasticContext emptyContextForTracer) {
6264
this.stackMaxDepth = stackMaxDepth;
65+
this.emptyContext = emptyContextForTracer;
6366
}
6467

6568
@Nullable
@@ -80,7 +83,7 @@ public ElasticContext<?> currentContext() {
8083
if (current instanceof ElasticContextWrapper) {
8184
return ((ElasticContextWrapper<?>) current).getWrappedContext();
8285
}
83-
return current != null ? current : EmptyElasticContext.INSTANCE;
86+
return current != null ? current : emptyContext;
8487
}
8588

8689
boolean activate(ElasticContext<?> context, List<ActivationListener> activationListeners) {

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,12 @@ public class ElasticApmTracer implements Tracer {
107107
private final Reporter reporter;
108108
private final ObjectPoolFactory objectPoolFactory;
109109

110+
private final EmptyElasticContext emptyContext;
111+
110112
private final ThreadLocal<ActiveStack> activeStack = new ThreadLocal<ActiveStack>() {
111113
@Override
112114
protected ActiveStack initialValue() {
113-
return new ActiveStack(transactionMaxSpans);
115+
return new ActiveStack(transactionMaxSpans, emptyContext);
114116
}
115117
};
116118

@@ -186,6 +188,7 @@ private static void checkClassloader() {
186188

187189
ElasticApmTracer(ConfigurationRegistry configurationRegistry, MetricRegistry metricRegistry, Reporter reporter, ObjectPoolFactory poolFactory,
188190
ApmServerClient apmServerClient, final String ephemeralId, MetaDataFuture metaDataFuture) {
191+
this.emptyContext = new EmptyElasticContext(this);
189192
this.metricRegistry = metricRegistry;
190193
this.configurationRegistry = configurationRegistry;
191194
this.reporter = reporter;

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/EmptyElasticContext.java

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@
2020

2121
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
2222
import co.elastic.apm.agent.impl.transaction.ElasticContext;
23-
import co.elastic.apm.agent.tracer.Scope;
2423

2524
import javax.annotation.Nullable;
2625

2726
class EmptyElasticContext extends ElasticContext<EmptyElasticContext> {
2827

29-
static final ElasticContext<?> INSTANCE = new EmptyElasticContext();
30-
31-
private EmptyElasticContext() {
28+
EmptyElasticContext(ElasticApmTracer tracer) {
29+
super(tracer);
3230
}
3331

3432
@Nullable
@@ -37,21 +35,6 @@ public AbstractSpan<?> getSpan() {
3735
return null;
3836
}
3937

40-
@Override
41-
public EmptyElasticContext activate() {
42-
return this;
43-
}
44-
45-
@Override
46-
public EmptyElasticContext deactivate() {
47-
return this;
48-
}
49-
50-
@Override
51-
public Scope activateInScope() {
52-
return NoopScope.INSTANCE;
53-
}
54-
5538
@Override
5639
public void incrementReferences() {
5740

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/AbstractSpan.java

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import co.elastic.apm.agent.sdk.logging.LoggerFactory;
2929
import co.elastic.apm.agent.sdk.internal.util.LoggerUtils;
3030
import co.elastic.apm.agent.tracer.Outcome;
31-
import co.elastic.apm.agent.tracer.Scope;
3231
import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderGetter;
3332
import co.elastic.apm.agent.tracer.dispatch.HeaderGetter;
3433
import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter;
@@ -55,7 +54,6 @@ public abstract class AbstractSpan<T extends AbstractSpan<T>> extends ElasticCon
5554
*/
5655
protected final StringBuilder name = new StringBuilder();
5756
protected final boolean collectBreakdownMetrics;
58-
protected final ElasticApmTracer tracer;
5957
protected final AtomicLong timestamp = new AtomicLong();
6058
protected final AtomicLong endTimestamp = new AtomicLong();
6159

@@ -197,7 +195,7 @@ public long getDuration() {
197195
}
198196

199197
public AbstractSpan(ElasticApmTracer tracer) {
200-
this.tracer = tracer;
198+
super(tracer);
201199
traceContext = TraceContext.with64BitId(this.tracer);
202200
boolean selfTimeCollectionEnabled = !WildcardMatcher.isAnyMatch(tracer.getConfig(ReporterConfiguration.class).getDisableMetrics(), "span.self_time");
203201
boolean breakdownMetricsEnabled = tracer.getConfig(CoreConfiguration.class).isBreakdownMetricsEnabled();
@@ -625,23 +623,6 @@ private boolean hasChildId(Id spanId) {
625623
*/
626624
public abstract Transaction getParentTransaction();
627625

628-
@Override
629-
public T activate() {
630-
tracer.activate(this);
631-
return thiz();
632-
}
633-
634-
@Override
635-
public T deactivate() {
636-
tracer.deactivate(this);
637-
return thiz();
638-
}
639-
640-
@Override
641-
public Scope activateInScope() {
642-
return tracer.activateInScope(this);
643-
}
644-
645626
/**
646627
* Set start timestamp
647628
*

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContext.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
package co.elastic.apm.agent.impl.transaction;
2020

21+
import co.elastic.apm.agent.impl.ElasticApmTracer;
22+
import co.elastic.apm.agent.tracer.Scope;
2123
import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderSetter;
2224
import co.elastic.apm.agent.tracer.dispatch.HeaderUtils;
2325
import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter;
@@ -27,6 +29,12 @@
2729

2830
public abstract class ElasticContext<T extends ElasticContext<T>> implements co.elastic.apm.agent.tracer.ElasticContext<T> {
2931

32+
protected final ElasticApmTracer tracer;
33+
34+
protected ElasticContext(ElasticApmTracer tracer) {
35+
this.tracer = tracer;
36+
}
37+
3038
@Nullable
3139
public abstract AbstractSpan<?> getSpan();
3240

@@ -39,6 +47,25 @@ public final Transaction getTransaction() {
3947
return contextSpan != null ? contextSpan.getParentTransaction() : null;
4048
}
4149

50+
@Override
51+
@SuppressWarnings("unchecked")
52+
public T activate() {
53+
tracer.activate(this);
54+
return (T) this;
55+
}
56+
57+
@Override
58+
@SuppressWarnings("unchecked")
59+
public T deactivate() {
60+
tracer.deactivate(this);
61+
return (T) this;
62+
}
63+
64+
@Override
65+
public Scope activateInScope() {
66+
return tracer.activateInScope(this);
67+
}
68+
4269
@Nullable
4370
@Override
4471
public co.elastic.apm.agent.impl.transaction.Span createSpan() {

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/transaction/ElasticContextWrapper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class ElasticContextWrapper<T extends ElasticContext<T>> extends ElasticC
5959
private final Map<Class<?>, ElasticContext<?>> contextWrappers;
6060

6161
public ElasticContextWrapper(int initialSize, ElasticContext<T> context) {
62+
super(context.tracer);
6263
this.contextWrappers = new HashMap<>(initialSize, 1.0f);
6364
this.context = context;
6465
}

apm-agent-core/src/test/java/co/elastic/apm/agent/impl/ElasticApmTracerTest.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,24 @@ void testActivateDeactivateTwice() {
544544
transaction.end();
545545
}
546546

547+
@Test
548+
void testEmptyContextActivation() {
549+
final Transaction transaction = startTestRootTransaction();
550+
assertThat(tracerImpl.currentContext().getTransaction()).isNull();
551+
tracerImpl.activate(transaction);
552+
assertThat(tracerImpl.currentContext().getTransaction()).isEqualTo(transaction);
553+
554+
EmptyElasticContext empty = new EmptyElasticContext(tracerImpl);
555+
empty.activate();
556+
assertThat(tracerImpl.currentContext().getTransaction()).isNull();
557+
558+
empty.deactivate();
559+
assertThat(tracerImpl.currentContext().getTransaction()).isEqualTo(transaction);
560+
tracerImpl.deactivate(transaction);
561+
assertThat(tracerImpl.currentContext().getTransaction()).isNull();
562+
transaction.end();
563+
}
564+
547565
@Test
548566
void testOverrideServiceNameWithoutExplicitServiceName() {
549567
final ElasticApmTracer tracer = new ElasticApmTracerBuilder()
@@ -714,19 +732,8 @@ void testUnknownConfiguration() {
714732

715733
private static final class TestContext extends ElasticContext<TestContext> {
716734

717-
@Override
718-
public TestContext activate() {
719-
return null;
720-
}
721-
722-
@Override
723-
public TestContext deactivate() {
724-
return null;
725-
}
726-
727-
@Override
728-
public Scope activateInScope() {
729-
return null;
735+
private TestContext() {
736+
super(null);
730737
}
731738

732739
@Nullable

apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-plugin/src/main/java/co/elastic/apm/agent/opentelemetry/tracing/OTelBridgeContext.java

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,8 @@ public class OTelBridgeContext extends ElasticContext<OTelBridgeContext> impleme
5151
*/
5252
private final Context otelContext;
5353

54-
private final ElasticApmTracer tracer;
55-
5654
private OTelBridgeContext(ElasticApmTracer tracer, Context otelContext) {
57-
this.tracer = tracer;
55+
super(tracer);
5856
this.otelContext = otelContext;
5957
}
6058

@@ -99,23 +97,6 @@ public static OTelBridgeContext wrapElasticActiveSpan(ElasticApmTracer tracer, A
9997
return new OTelBridgeContext(tracer, originalRootContext.with(otelSpan));
10098
}
10199

102-
@Override
103-
public OTelBridgeContext activate() {
104-
tracer.activate(this);
105-
return this;
106-
}
107-
108-
@Override
109-
public co.elastic.apm.agent.tracer.Scope activateInScope() {
110-
return tracer.activateInScope(this);
111-
}
112-
113-
@Override
114-
public OTelBridgeContext deactivate() {
115-
tracer.deactivate(this);
116-
return this;
117-
}
118-
119100
@Nullable
120101
@Override
121102
public AbstractSpan<?> getSpan() {

0 commit comments

Comments
 (0)