13
13
import application .io .opentelemetry .context .Scope ;
14
14
import io .opentelemetry .javaagent .instrumentation .opentelemetryapi .baggage .BaggageBridging ;
15
15
import io .opentelemetry .javaagent .instrumentation .opentelemetryapi .trace .Bridging ;
16
+ import java .lang .invoke .MethodHandle ;
17
+ import java .lang .invoke .MethodHandles ;
18
+ import java .lang .invoke .MethodType ;
16
19
import java .lang .reflect .Field ;
17
20
import java .util .function .Function ;
18
21
import org .checkerframework .checker .nullness .qual .Nullable ;
@@ -39,7 +42,80 @@ public class AgentContextStorage implements ContextStorage, AutoCloseable {
39
42
40
43
private static final Logger logger = LoggerFactory .getLogger (AgentContextStorage .class );
41
44
42
- public static final AgentContextStorage INSTANCE = new AgentContextStorage ();
45
+ // MethodHandle for ContextStorage.root() that was added in 1.5
46
+ private static final MethodHandle CONTEXT_STORAGE_ROOT_HANDLE = getContextStorageRootHandle ();
47
+
48
+ // unwrapped application root context
49
+ private final Context applicationRoot ;
50
+ // wrapped application root context
51
+ private final Context root ;
52
+
53
+ private AgentContextStorage (ContextStorage delegate ) {
54
+ applicationRoot = getRootContext (delegate );
55
+ root = getWrappedRootContext (applicationRoot );
56
+ }
57
+
58
+ private static MethodHandle getContextStorageRootHandle () {
59
+ try {
60
+ return MethodHandles .lookup ()
61
+ .findVirtual (ContextStorage .class , "root" , MethodType .methodType (Context .class ));
62
+ } catch (NoSuchMethodException | IllegalAccessException exception ) {
63
+ return null ;
64
+ }
65
+ }
66
+
67
+ private static boolean has15Api () {
68
+ return CONTEXT_STORAGE_ROOT_HANDLE != null ;
69
+ }
70
+
71
+ private static Context getRootContext (ContextStorage contextStorage ) {
72
+ if (has15Api ()) {
73
+ // when bridging to 1.5 api call ContextStorage.root()
74
+ try {
75
+ return (Context ) CONTEXT_STORAGE_ROOT_HANDLE .invoke (contextStorage );
76
+ } catch (Throwable throwable ) {
77
+ throw new IllegalStateException ("Failed to get root context" , throwable );
78
+ }
79
+ } else {
80
+ return RootContextHolder .APPLICATION_ROOT ;
81
+ }
82
+ }
83
+
84
+ private static Context getWrappedRootContext (Context rootContext ) {
85
+ if (has15Api ()) {
86
+ return new AgentContextWrapper (io .opentelemetry .context .Context .root (), rootContext );
87
+ }
88
+ return RootContextHolder .ROOT ;
89
+ }
90
+
91
+ public static Context wrapRootContext (Context rootContext ) {
92
+ if (has15Api ()) {
93
+ return rootContext ;
94
+ }
95
+ return RootContextHolder .getRootContext (rootContext );
96
+ }
97
+
98
+ // helper class for keeping track of root context when bridging to api earlier than 1.5
99
+ private static class RootContextHolder {
100
+ // unwrapped application root context
101
+ static final Context APPLICATION_ROOT = Context .root ();
102
+ // wrapped application root context
103
+ static final Context ROOT =
104
+ new AgentContextWrapper (io .opentelemetry .context .Context .root (), APPLICATION_ROOT );
105
+
106
+ static Context getRootContext (Context rootContext ) {
107
+ // APPLICATION_ROOT is null when this method is called while the static initializer is
108
+ // initializing the value of APPLICATION_ROOT field
109
+ if (RootContextHolder .APPLICATION_ROOT == null ) {
110
+ return rootContext ;
111
+ }
112
+ return RootContextHolder .ROOT ;
113
+ }
114
+ }
115
+
116
+ public static Function <? super ContextStorage , ? extends ContextStorage > wrap () {
117
+ return contextStorage -> new AgentContextStorage (contextStorage );
118
+ }
43
119
44
120
public static io .opentelemetry .context .Context getAgentContext (Context applicationContext ) {
45
121
if (applicationContext instanceof AgentContextWrapper ) {
@@ -54,6 +130,9 @@ public static io.opentelemetry.context.Context getAgentContext(Context applicati
54
130
55
131
public static Context newContextWrapper (
56
132
io .opentelemetry .context .Context agentContext , Context applicationContext ) {
133
+ if (applicationContext instanceof AgentContextWrapper ) {
134
+ applicationContext = ((AgentContextWrapper ) applicationContext ).applicationContext ;
135
+ }
57
136
return new AgentContextWrapper (agentContext , applicationContext );
58
137
}
59
138
@@ -80,16 +159,17 @@ public Scope attach(Context toAttach) {
80
159
io .opentelemetry .context .Context .current ();
81
160
Context currentApplicationContext = currentAgentContext .get (APPLICATION_CONTEXT );
82
161
if (currentApplicationContext == null ) {
83
- currentApplicationContext = Context .root ();
84
- }
85
-
86
- if (currentApplicationContext == toAttach ) {
87
- return Scope .noop ();
162
+ currentApplicationContext = applicationRoot ;
88
163
}
89
164
90
165
io .opentelemetry .context .Context newAgentContext ;
91
166
if (toAttach instanceof AgentContextWrapper ) {
92
- newAgentContext = ((AgentContextWrapper ) toAttach ).toAgentContext ();
167
+ AgentContextWrapper wrapper = (AgentContextWrapper ) toAttach ;
168
+ if (currentApplicationContext == wrapper .applicationContext
169
+ && currentAgentContext == wrapper .agentContext ) {
170
+ return Scope .noop ();
171
+ }
172
+ newAgentContext = wrapper .toAgentContext ();
93
173
} else {
94
174
newAgentContext = currentAgentContext .with (APPLICATION_CONTEXT , toAttach );
95
175
}
@@ -102,9 +182,18 @@ public Context current() {
102
182
io .opentelemetry .context .Context agentContext = io .opentelemetry .context .Context .current ();
103
183
Context applicationContext = agentContext .get (APPLICATION_CONTEXT );
104
184
if (applicationContext == null ) {
105
- applicationContext = Context . root () ;
185
+ applicationContext = applicationRoot ;
106
186
}
107
- return new AgentContextWrapper (io .opentelemetry .context .Context .current (), applicationContext );
187
+ if (applicationContext == applicationRoot
188
+ && agentContext == io .opentelemetry .context .Context .root ()) {
189
+ return root ;
190
+ }
191
+ return new AgentContextWrapper (agentContext , applicationContext );
192
+ }
193
+
194
+ @ Override
195
+ public Context root () {
196
+ return root ;
108
197
}
109
198
110
199
@ Override
@@ -121,6 +210,9 @@ private static class AgentContextWrapper implements Context {
121
210
final Context applicationContext ;
122
211
123
212
AgentContextWrapper (io .opentelemetry .context .Context agentContext , Context applicationContext ) {
213
+ if (applicationContext instanceof AgentContextWrapper ) {
214
+ throw new IllegalStateException ("Expected unwrapped context" );
215
+ }
124
216
this .agentContext = agentContext ;
125
217
this .applicationContext = applicationContext ;
126
218
}
0 commit comments