9
9
import io .opentelemetry .context .Context ;
10
10
import io .opentelemetry .context .ContextKey ;
11
11
import io .opentelemetry .context .Scope ;
12
+ import java .util .Arrays ;
12
13
import javax .annotation .Nullable ;
13
14
import javax .annotation .ParametersAreNonnullByDefault ;
14
15
15
16
@ ParametersAreNonnullByDefault
16
17
public class OtelContext implements Context {
18
+ private static final Object [] NO_ENTRIES = {};
19
+
17
20
/** Overridden root context. */
18
21
public static final OtelContext ROOT = new OtelContext (OtelSpan .invalid (), OtelSpan .invalid ());
19
22
@@ -26,30 +29,60 @@ public class OtelContext implements Context {
26
29
private final Span currentSpan ;
27
30
private final Span rootSpan ;
28
31
32
+ private final Object [] entries ;
33
+
29
34
public OtelContext (Span currentSpan , Span rootSpan ) {
35
+ this (currentSpan , rootSpan , NO_ENTRIES );
36
+ }
37
+
38
+ public OtelContext (Span currentSpan , Span rootSpan , Object [] entries ) {
30
39
this .currentSpan = currentSpan ;
31
40
this .rootSpan = rootSpan ;
41
+ this .entries = entries ;
32
42
}
33
43
34
44
@ Nullable
35
45
@ Override
46
+ @ SuppressWarnings ("unchecked" )
36
47
public <V > V get (ContextKey <V > key ) {
37
48
if (OTEL_CONTEXT_SPAN_KEY .equals (key .toString ())) {
38
49
return (V ) this .currentSpan ;
39
50
} else if (OTEL_CONTEXT_ROOT_SPAN_KEY .equals (key .toString ())) {
40
51
return (V ) this .rootSpan ;
41
52
}
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
+ }
42
58
return null ;
43
59
}
44
60
45
61
@ 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
+ }
51
79
}
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 );
53
86
}
54
87
55
88
@ Override
@@ -59,7 +92,7 @@ public Scope makeCurrent() {
59
92
// only keep propagated context until next span activation
60
93
lastPropagated .remove ();
61
94
AgentScope agentScope = ((OtelSpan ) this .currentSpan ).activate ();
62
- return new OtelScope (scope , agentScope );
95
+ return new OtelScope (scope , agentScope , this . entries );
63
96
} else {
64
97
// propagated context not on the scope stack, capture it here
65
98
lastPropagated .set (this );
@@ -80,12 +113,13 @@ public static Context current() {
80
113
return context ;
81
114
}
82
115
// Check empty context
83
- AgentSpan agentCurrentSpan = AgentTracer .activeSpan ();
84
- if (null == agentCurrentSpan ) {
116
+ AgentScope agentCurrentScope = AgentTracer .activeScope ();
117
+ if (null == agentCurrentScope ) {
85
118
return OtelContext .ROOT ;
86
119
}
87
120
// Get OTel current span
88
121
Span otelCurrentSpan = null ;
122
+ AgentSpan agentCurrentSpan = agentCurrentScope .span ();
89
123
if (agentCurrentSpan instanceof AttachableWrapper ) {
90
124
Object wrapper = ((AttachableWrapper ) agentCurrentSpan ).getWrapper ();
91
125
if (wrapper instanceof OtelSpan ) {
@@ -107,7 +141,15 @@ public static Context current() {
107
141
if (otelRootSpan == null ) {
108
142
otelRootSpan = new OtelSpan (agentRootSpan );
109
143
}
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 );
111
153
}
112
154
113
155
/** Last propagated context not on the scope stack; {@code null} if there's no such context. */
0 commit comments