16
16
17
17
package org .springframework .graphql .observation ;
18
18
19
- import java .util .concurrent .CompletionStage ;
20
-
21
19
import graphql .ExecutionResult ;
22
- import graphql .GraphQLContext ;
20
+ import graphql .execution .ExecutionStepInfo ;
21
+ import graphql .execution .ResultPath ;
23
22
import graphql .execution .instrumentation .InstrumentationContext ;
24
23
import graphql .execution .instrumentation .InstrumentationState ;
25
24
import graphql .execution .instrumentation .SimpleInstrumentation ;
30
29
import graphql .schema .DataFetcher ;
31
30
import io .micrometer .observation .Observation ;
32
31
import io .micrometer .observation .ObservationRegistry ;
32
+ import io .micrometer .observation .contextpropagation .ObservationThreadLocalAccessor ;
33
+
34
+ import java .util .concurrent .CompletionStage ;
35
+ import java .util .concurrent .ConcurrentHashMap ;
33
36
34
37
/**
35
38
* {@link SimpleInstrumentation} that creates {@link Observation observations}
50
53
*/
51
54
public class GraphQlObservationInstrumentation extends SimpleInstrumentation {
52
55
53
- private static final String OBSERVATION_KEY = "micrometer.observation" ;
54
-
55
56
private static final ExecutionRequestObservationConvention DEFAULT_REQUEST_CONVENTION =
56
57
new DefaultExecutionRequestObservationConvention ();
57
58
@@ -101,11 +102,10 @@ public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExe
101
102
InstrumentationState state ) {
102
103
if (state instanceof RequestObservationInstrumentationState instrumentationState ) {
103
104
ExecutionRequestObservationContext observationContext = new ExecutionRequestObservationContext (parameters .getExecutionInput ());
104
- Observation parentObservation = parameters .getGraphQLContext ().get (OBSERVATION_KEY );
105
+ Observation parentObservation = parameters .getGraphQLContext ().get (ObservationThreadLocalAccessor . KEY );
105
106
Observation requestObservation = instrumentationState .createRequestObservation (this .requestObservationConvention ,
106
107
observationContext , this .observationRegistry );
107
108
requestObservation .parentObservation (parentObservation );
108
- parameters .getGraphQLContext ().put (OBSERVATION_KEY , requestObservation );
109
109
requestObservation .start ();
110
110
return new SimpleInstrumentationContext <>() {
111
111
@ Override
@@ -115,7 +115,6 @@ public void onCompleted(ExecutionResult result, Throwable exc) {
115
115
requestObservation .error (exc );
116
116
}
117
117
requestObservation .stop ();
118
- instrumentationState .restoreParentObservation (parameters .getGraphQLContext (), parentObservation );
119
118
}
120
119
};
121
120
}
@@ -128,13 +127,8 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
128
127
if (!parameters .isTrivialDataFetcher ()
129
128
&& state instanceof RequestObservationInstrumentationState instrumentationState ) {
130
129
return (environment ) -> {
131
- GraphQLContext graphQLContext = parameters .getExecutionContext ().getGraphQLContext ();
132
- Observation parentObservation = graphQLContext .get (OBSERVATION_KEY );
133
130
DataFetcherObservationContext observationContext = new DataFetcherObservationContext (parameters .getEnvironment ());
134
- Observation dataFetcherObservation = instrumentationState .createDataFetcherObservation (
135
- this .dataFetcherObservationConvention , observationContext , this .observationRegistry );
136
- dataFetcherObservation .parentObservation (parentObservation );
137
- graphQLContext .put (OBSERVATION_KEY , dataFetcherObservation );
131
+ Observation dataFetcherObservation = instrumentationState .createDataFetcherObservation (this .dataFetcherObservationConvention , observationContext , this .observationRegistry );
138
132
dataFetcherObservation .start ();
139
133
try {
140
134
Object value = dataFetcher .get (environment );
@@ -145,20 +139,17 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
145
139
dataFetcherObservation .error (error );
146
140
}
147
141
dataFetcherObservation .stop ();
148
- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
149
142
});
150
143
}
151
144
else {
152
145
observationContext .setValue (value );
153
146
dataFetcherObservation .stop ();
154
- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
155
147
return value ;
156
148
}
157
149
}
158
150
catch (Throwable throwable ) {
159
151
dataFetcherObservation .error (throwable );
160
152
dataFetcherObservation .stop ();
161
- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
162
153
throw throwable ;
163
154
}
164
155
};
@@ -169,25 +160,28 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
169
160
170
161
static class RequestObservationInstrumentationState implements InstrumentationState {
171
162
163
+ private Observation requestObservation ;
164
+
165
+ private final ConcurrentHashMap <ResultPath , Observation > activeObservations = new ConcurrentHashMap <>(8 );
166
+
172
167
Observation createRequestObservation (ExecutionRequestObservationConvention convention ,
173
- ExecutionRequestObservationContext context , ObservationRegistry registry ) {
174
- return GraphQlObservationDocumentation .EXECUTION_REQUEST .observation (convention ,
168
+ ExecutionRequestObservationContext context , ObservationRegistry registry ) {
169
+ Observation observation = GraphQlObservationDocumentation .EXECUTION_REQUEST .observation (convention ,
175
170
DEFAULT_REQUEST_CONVENTION , () -> context , registry );
171
+ this .requestObservation = observation ;
172
+ return observation ;
176
173
}
177
174
178
175
Observation createDataFetcherObservation (DataFetcherObservationConvention convention ,
179
- DataFetcherObservationContext context , ObservationRegistry registry ) {
180
- return GraphQlObservationDocumentation .DATA_FETCHER .observation (convention ,
176
+ DataFetcherObservationContext context , ObservationRegistry registry ) {
177
+ ExecutionStepInfo executionStepInfo = context .getEnvironment ().getExecutionStepInfo ();
178
+ Observation observation = GraphQlObservationDocumentation .DATA_FETCHER .observation (convention ,
181
179
DEFAULT_DATA_FETCHER_CONVENTION , () -> context , registry );
182
- }
183
-
184
- void restoreParentObservation (GraphQLContext context , Observation parentObservation ) {
185
- if (parentObservation != null ) {
186
- context .put (OBSERVATION_KEY , parentObservation );
187
- }
188
- else {
189
- context .delete (OBSERVATION_KEY );
190
- }
180
+ Observation parentObservation = (executionStepInfo .hasParent ()) ? this .activeObservations .getOrDefault (executionStepInfo .getParent ().getPath (), this .requestObservation )
181
+ : this .requestObservation ;
182
+ observation .parentObservation (parentObservation );
183
+ this .activeObservations .put (executionStepInfo .getPath (), observation );
184
+ return observation ;
191
185
}
192
186
193
187
}
0 commit comments