Skip to content

Commit 64a0120

Browse files
authored
Support custom OpenTelemetry context values (#7118)
1 parent 23584d8 commit 64a0120

File tree

3 files changed

+60
-13
lines changed

3 files changed

+60
-13
lines changed

dd-java-agent/agent-otel/otel-shim/src/main/java/datadog/opentelemetry/shim/context/OtelContext.java

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
import io.opentelemetry.context.Context;
1010
import io.opentelemetry.context.ContextKey;
1111
import io.opentelemetry.context.Scope;
12+
import java.util.Arrays;
1213
import javax.annotation.Nullable;
1314
import javax.annotation.ParametersAreNonnullByDefault;
1415

1516
@ParametersAreNonnullByDefault
1617
public class OtelContext implements Context {
18+
private static final Object[] NO_ENTRIES = {};
19+
1720
/** Overridden root context. */
1821
public static final OtelContext ROOT = new OtelContext(OtelSpan.invalid(), OtelSpan.invalid());
1922

@@ -26,30 +29,60 @@ public class OtelContext implements Context {
2629
private final Span currentSpan;
2730
private final Span rootSpan;
2831

32+
private final Object[] entries;
33+
2934
public OtelContext(Span currentSpan, Span rootSpan) {
35+
this(currentSpan, rootSpan, NO_ENTRIES);
36+
}
37+
38+
public OtelContext(Span currentSpan, Span rootSpan, Object[] entries) {
3039
this.currentSpan = currentSpan;
3140
this.rootSpan = rootSpan;
41+
this.entries = entries;
3242
}
3343

3444
@Nullable
3545
@Override
46+
@SuppressWarnings("unchecked")
3647
public <V> V get(ContextKey<V> key) {
3748
if (OTEL_CONTEXT_SPAN_KEY.equals(key.toString())) {
3849
return (V) this.currentSpan;
3950
} else if (OTEL_CONTEXT_ROOT_SPAN_KEY.equals(key.toString())) {
4051
return (V) this.rootSpan;
4152
}
53+
for (int i = 0; i < this.entries.length; i += 2) {
54+
if (this.entries[i] == key) {
55+
return (V) this.entries[i + 1];
56+
}
57+
}
4258
return null;
4359
}
4460

4561
@Override
46-
public <V> Context with(ContextKey<V> k1, V v1) {
47-
if (OTEL_CONTEXT_SPAN_KEY.equals(k1.toString())) {
48-
return new OtelContext((Span) v1, this.rootSpan);
49-
} else if (OTEL_CONTEXT_ROOT_SPAN_KEY.equals(k1.toString())) {
50-
return new OtelContext(this.currentSpan, (Span) v1);
62+
public <V> Context with(ContextKey<V> key, V value) {
63+
if (OTEL_CONTEXT_SPAN_KEY.equals(key.toString())) {
64+
return new OtelContext((Span) value, this.rootSpan, this.entries);
65+
} else if (OTEL_CONTEXT_ROOT_SPAN_KEY.equals(key.toString())) {
66+
return new OtelContext(this.currentSpan, (Span) value, this.entries);
67+
}
68+
Object[] newEntries = null;
69+
int oldEntriesLength = this.entries.length;
70+
for (int i = 0; i < oldEntriesLength; i += 2) {
71+
if (this.entries[i] == key) {
72+
if (this.entries[i + 1] == value) {
73+
return this;
74+
}
75+
newEntries = this.entries.clone();
76+
newEntries[i + 1] = value;
77+
break;
78+
}
5179
}
52-
return this;
80+
if (null == newEntries) {
81+
newEntries = Arrays.copyOf(this.entries, oldEntriesLength + 2);
82+
newEntries[oldEntriesLength] = key;
83+
newEntries[oldEntriesLength + 1] = value;
84+
}
85+
return new OtelContext(this.currentSpan, this.rootSpan, newEntries);
5386
}
5487

5588
@Override
@@ -59,7 +92,7 @@ public Scope makeCurrent() {
5992
// only keep propagated context until next span activation
6093
lastPropagated.remove();
6194
AgentScope agentScope = ((OtelSpan) this.currentSpan).activate();
62-
return new OtelScope(scope, agentScope);
95+
return new OtelScope(scope, agentScope, this.entries);
6396
} else {
6497
// propagated context not on the scope stack, capture it here
6598
lastPropagated.set(this);
@@ -80,12 +113,13 @@ public static Context current() {
80113
return context;
81114
}
82115
// Check empty context
83-
AgentSpan agentCurrentSpan = AgentTracer.activeSpan();
84-
if (null == agentCurrentSpan) {
116+
AgentScope agentCurrentScope = AgentTracer.activeScope();
117+
if (null == agentCurrentScope) {
85118
return OtelContext.ROOT;
86119
}
87120
// Get OTel current span
88121
Span otelCurrentSpan = null;
122+
AgentSpan agentCurrentSpan = agentCurrentScope.span();
89123
if (agentCurrentSpan instanceof AttachableWrapper) {
90124
Object wrapper = ((AttachableWrapper) agentCurrentSpan).getWrapper();
91125
if (wrapper instanceof OtelSpan) {
@@ -107,7 +141,15 @@ public static Context current() {
107141
if (otelRootSpan == null) {
108142
otelRootSpan = new OtelSpan(agentRootSpan);
109143
}
110-
return new OtelContext(otelCurrentSpan, otelRootSpan);
144+
// Get OTel custom context entries
145+
Object[] contextEntries = NO_ENTRIES;
146+
if (agentCurrentScope instanceof AttachableWrapper) {
147+
Object wrapper = ((AttachableWrapper) agentCurrentScope).getWrapper();
148+
if (wrapper instanceof OtelScope) {
149+
contextEntries = ((OtelScope) wrapper).contextEntries();
150+
}
151+
}
152+
return new OtelContext(otelCurrentSpan, otelRootSpan, contextEntries);
111153
}
112154

113155
/** Last propagated context not on the scope stack; {@code null} if there's no such context. */

dd-java-agent/agent-otel/otel-shim/src/main/java/datadog/opentelemetry/shim/context/OtelScope.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,22 @@
77
public class OtelScope implements Scope {
88
private final Scope scope;
99
private final AgentScope delegate;
10+
private final Object[] contextEntries;
1011

11-
public OtelScope(Scope scope, AgentScope delegate) {
12+
public OtelScope(Scope scope, AgentScope delegate, Object[] contextEntries) {
1213
this.scope = scope;
1314
this.delegate = delegate;
15+
this.contextEntries = contextEntries;
1416
if (delegate instanceof AttachableWrapper) {
1517
((AttachableWrapper) delegate).attachWrapper(this);
1618
}
1719
}
1820

21+
/** Context entries from {@link OtelContext}, captured when the context was made current. */
22+
Object[] contextEntries() {
23+
return contextEntries;
24+
}
25+
1926
@Override
2027
public void close() {
2128
this.delegate.close();

dd-java-agent/instrumentation/opentelemetry/opentelemetry-1.4/src/test/groovy/opentelemetry14/context/ContextTest.groovy

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import io.opentelemetry.context.Context
88
import io.opentelemetry.context.ContextKey
99
import io.opentelemetry.context.ImplicitContextKeyed
1010
import io.opentelemetry.context.ThreadLocalContextStorage
11-
import spock.lang.Ignore
1211
import spock.lang.Subject
1312

1413
import static datadog.trace.bootstrap.instrumentation.api.ScopeSource.MANUAL
@@ -279,7 +278,6 @@ class ContextTest extends AgentTestRunner {
279278
parentSpan.end()
280279
}
281280

282-
@Ignore("Not supported")
283281
def "test custom object storage"() {
284282
setup:
285283
def context = Context.root()

0 commit comments

Comments
 (0)