@@ -44,6 +44,24 @@ type PluginContext = {
44
44
[ tracingSpanSymbol ] : opentelemetry . Span ;
45
45
} ;
46
46
47
+ export const otelContextMap = new WeakMap < any , opentelemetry . Context > ( ) ;
48
+
49
+ export function getCurrentOtelContext ( graphqlContext : any ) : opentelemetry . Context {
50
+ let otelContext = otelContextMap . get ( graphqlContext ) ;
51
+
52
+ if ( ! otelContext ) {
53
+ otelContext = opentelemetry . context . active ( ) ;
54
+ otelContextMap . set ( graphqlContext , otelContext ) ;
55
+ }
56
+
57
+ return otelContext ;
58
+ }
59
+
60
+ export function setCurrentOtelContext ( graphqlContext : any , otelContext : opentelemetry . Context ) {
61
+ otelContextMap . set ( graphqlContext , otelContext ) ;
62
+ return otelContext ;
63
+ }
64
+
47
65
export const useOpenTelemetry = (
48
66
options : TracingOptions ,
49
67
tracingProvider ?: TracerProvider ,
@@ -70,7 +88,7 @@ export const useOpenTelemetry = (
70
88
useOnResolve ( ( { info, context, args } ) => {
71
89
const parentSpan = spanByContext . get ( context ) ;
72
90
if ( parentSpan ) {
73
- const ctx = opentelemetry . trace . setSpan ( opentelemetry . context . active ( ) , parentSpan ) ;
91
+ const ctx = opentelemetry . trace . setSpan ( getCurrentOtelContext ( context ) , parentSpan ) ;
74
92
const { fieldName, returnType, parentType } = info ;
75
93
76
94
const resolverSpan = tracer . startSpan (
@@ -103,7 +121,12 @@ export const useOpenTelemetry = (
103
121
) ;
104
122
}
105
123
} ,
106
- onExecute ( { args } ) {
124
+ onExecute ( { args, executeFn, setExecuteFn } ) {
125
+ setExecuteFn ( function wrappedExecuteFnWithOtelCtx ( args ) {
126
+ return opentelemetry . context . with ( getCurrentOtelContext ( args . contextValue ) , ( ) =>
127
+ executeFn ( args ) ,
128
+ ) ;
129
+ } ) ;
107
130
const operationAst = getOperationAST ( args . document , args . operationName ) ;
108
131
if ( ! operationAst ) {
109
132
return ;
@@ -122,24 +145,29 @@ export const useOpenTelemetry = (
122
145
isDocumentLoggable = false ;
123
146
}
124
147
const operationName = operationAst . name ?. value || 'anonymous' ;
125
- const executionSpan = tracer . startSpan ( `${ spanPrefix } ${ operationType } .${ operationName } ` , {
126
- kind : spanKind ,
127
- attributes : {
128
- ...spanAdditionalAttributes ,
129
- [ AttributeName . EXECUTION_OPERATION_NAME ] : operationName ,
130
- [ AttributeName . EXECUTION_OPERATION_TYPE ] : operationType ,
131
- [ AttributeName . EXECUTION_OPERATION_DOCUMENT ] : isDocumentLoggable
132
- ? getDocumentString ( args . document , print )
133
- : undefined ,
134
- ...( options . variables
135
- ? { [ AttributeName . EXECUTION_VARIABLES ] : JSON . stringify ( args . variableValues ?? { } ) }
136
- : { } ) ,
148
+ const currOtelContext = getCurrentOtelContext ( args . contextValue ) ;
149
+ const executionSpan = tracer . startSpan (
150
+ `${ spanPrefix } ${ operationType } .${ operationName } ` ,
151
+ {
152
+ kind : spanKind ,
153
+ attributes : {
154
+ ...spanAdditionalAttributes ,
155
+ [ AttributeName . EXECUTION_OPERATION_NAME ] : operationName ,
156
+ [ AttributeName . EXECUTION_OPERATION_TYPE ] : operationType ,
157
+ [ AttributeName . EXECUTION_OPERATION_DOCUMENT ] : isDocumentLoggable
158
+ ? getDocumentString ( args . document , print )
159
+ : undefined ,
160
+ ...( options . variables
161
+ ? { [ AttributeName . EXECUTION_VARIABLES ] : JSON . stringify ( args . variableValues ?? { } ) }
162
+ : { } ) ,
163
+ } ,
137
164
} ,
138
- } ) ;
165
+ currOtelContext ,
166
+ ) ;
139
167
140
- const otelContext = opentelemetry . trace . setSpan (
141
- opentelemetry . context . active ( ) ,
142
- executionSpan ,
168
+ setCurrentOtelContext (
169
+ args . contextValue ,
170
+ opentelemetry . trace . setSpan ( currOtelContext , executionSpan ) ,
143
171
) ;
144
172
145
173
const resultCbs : OnExecuteHookResult < PluginContext > = {
@@ -149,7 +177,8 @@ export const useOpenTelemetry = (
149
177
executionSpan . setAttribute ( AttributeName . EXECUTION_RESULT , JSON . stringify ( result ) ) ;
150
178
}
151
179
if ( options . traceIdInResult ) {
152
- setResult ( addTraceIdToResult ( otelContext , result , options . traceIdInResult ) ) ;
180
+ const currOtelContext = getCurrentOtelContext ( args . contextValue ) ;
181
+ setResult ( addTraceIdToResult ( currOtelContext , result , options . traceIdInResult ) ) ;
153
182
}
154
183
markError ( executionSpan , result ) ;
155
184
executionSpan . end ( ) ;
@@ -159,7 +188,8 @@ export const useOpenTelemetry = (
159
188
// handles async iterator
160
189
onNext : ( { result, setResult } ) => {
161
190
if ( options . traceIdInResult ) {
162
- setResult ( addTraceIdToResult ( otelContext , result , options . traceIdInResult ) ) ;
191
+ const currOtelContext = getCurrentOtelContext ( args . contextValue ) ;
192
+ setResult ( addTraceIdToResult ( currOtelContext , result , options . traceIdInResult ) ) ;
163
193
}
164
194
markError ( executionSpan , result ) ;
165
195
} ,
@@ -176,7 +206,12 @@ export const useOpenTelemetry = (
176
206
177
207
return resultCbs ;
178
208
} ,
179
- onSubscribe ( { args } ) {
209
+ onSubscribe ( { args, subscribeFn, setSubscribeFn } ) {
210
+ setSubscribeFn ( function wrappedSubscribeFnWithOtelCtx ( args ) {
211
+ return opentelemetry . context . with ( getCurrentOtelContext ( args . contextValue ) , ( ) =>
212
+ subscribeFn ( args ) ,
213
+ ) ;
214
+ } ) ;
180
215
const operationAst = getOperationAST ( args . document , args . operationName ) ;
181
216
if ( ! operationAst ) {
182
217
return ;
@@ -190,25 +225,30 @@ export const useOpenTelemetry = (
190
225
} else {
191
226
isDocumentLoggable = false ;
192
227
}
228
+ const currOtelContext = getCurrentOtelContext ( args . contextValue ) ;
193
229
const operationName = operationAst . name ?. value || 'anonymous' ;
194
- const subscriptionSpan = tracer . startSpan ( `${ operationType } .${ operationName } ` , {
195
- kind : spanKind ,
196
- attributes : {
197
- ...spanAdditionalAttributes ,
198
- [ AttributeName . EXECUTION_OPERATION_NAME ] : operationName ,
199
- [ AttributeName . EXECUTION_OPERATION_TYPE ] : operationType ,
200
- [ AttributeName . EXECUTION_OPERATION_DOCUMENT ] : isDocumentLoggable
201
- ? getDocumentString ( args . document , print )
202
- : undefined ,
203
- ...( options . variables
204
- ? { [ AttributeName . EXECUTION_VARIABLES ] : JSON . stringify ( args . variableValues ?? { } ) }
205
- : { } ) ,
230
+ const subscriptionSpan = tracer . startSpan (
231
+ `${ operationType } .${ operationName } ` ,
232
+ {
233
+ kind : spanKind ,
234
+ attributes : {
235
+ ...spanAdditionalAttributes ,
236
+ [ AttributeName . EXECUTION_OPERATION_NAME ] : operationName ,
237
+ [ AttributeName . EXECUTION_OPERATION_TYPE ] : operationType ,
238
+ [ AttributeName . EXECUTION_OPERATION_DOCUMENT ] : isDocumentLoggable
239
+ ? getDocumentString ( args . document , print )
240
+ : undefined ,
241
+ ...( options . variables
242
+ ? { [ AttributeName . EXECUTION_VARIABLES ] : JSON . stringify ( args . variableValues ?? { } ) }
243
+ : { } ) ,
244
+ } ,
206
245
} ,
207
- } ) ;
246
+ currOtelContext ,
247
+ ) ;
208
248
209
- const otelContext = opentelemetry . trace . setSpan (
210
- opentelemetry . context . active ( ) ,
211
- subscriptionSpan ,
249
+ setCurrentOtelContext (
250
+ args . contextValue ,
251
+ opentelemetry . trace . setSpan ( currOtelContext , subscriptionSpan ) ,
212
252
) ;
213
253
214
254
const resultCbs : OnSubscribeHookResult < PluginContext > = {
@@ -220,7 +260,8 @@ export const useOpenTelemetry = (
220
260
// handles async iterator
221
261
onNext : ( { result, setResult } ) => {
222
262
if ( options . traceIdInResult ) {
223
- setResult ( addTraceIdToResult ( otelContext , result , options . traceIdInResult ) ) ;
263
+ const currOtelContext = getCurrentOtelContext ( args . contextValue ) ;
264
+ setResult ( addTraceIdToResult ( currOtelContext , result , options . traceIdInResult ) ) ;
224
265
}
225
266
markError ( subscriptionSpan , result ) ;
226
267
} ,
0 commit comments