1616
1717package org .springframework .graphql .observation ;
1818
19- import java .util .concurrent .CompletionStage ;
20-
2119import graphql .ExecutionResult ;
22- import graphql .GraphQLContext ;
20+ import graphql .execution .ExecutionStepInfo ;
21+ import graphql .execution .ResultPath ;
2322import graphql .execution .instrumentation .InstrumentationContext ;
2423import graphql .execution .instrumentation .InstrumentationState ;
2524import graphql .execution .instrumentation .SimpleInstrumentation ;
3029import graphql .schema .DataFetcher ;
3130import io .micrometer .observation .Observation ;
3231import io .micrometer .observation .ObservationRegistry ;
32+ import io .micrometer .observation .contextpropagation .ObservationThreadLocalAccessor ;
33+
34+ import java .util .concurrent .CompletionStage ;
35+ import java .util .concurrent .ConcurrentHashMap ;
3336
3437/**
3538 * {@link SimpleInstrumentation} that creates {@link Observation observations}
5053 */
5154public class GraphQlObservationInstrumentation extends SimpleInstrumentation {
5255
53- private static final String OBSERVATION_KEY = "micrometer.observation" ;
54-
5556 private static final ExecutionRequestObservationConvention DEFAULT_REQUEST_CONVENTION =
5657 new DefaultExecutionRequestObservationConvention ();
5758
@@ -101,11 +102,10 @@ public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExe
101102 InstrumentationState state ) {
102103 if (state instanceof RequestObservationInstrumentationState instrumentationState ) {
103104 ExecutionRequestObservationContext observationContext = new ExecutionRequestObservationContext (parameters .getExecutionInput ());
104- Observation parentObservation = parameters .getGraphQLContext ().get (OBSERVATION_KEY );
105+ Observation parentObservation = parameters .getGraphQLContext ().get (ObservationThreadLocalAccessor . KEY );
105106 Observation requestObservation = instrumentationState .createRequestObservation (this .requestObservationConvention ,
106107 observationContext , this .observationRegistry );
107108 requestObservation .parentObservation (parentObservation );
108- parameters .getGraphQLContext ().put (OBSERVATION_KEY , requestObservation );
109109 requestObservation .start ();
110110 return new SimpleInstrumentationContext <>() {
111111 @ Override
@@ -115,7 +115,6 @@ public void onCompleted(ExecutionResult result, Throwable exc) {
115115 requestObservation .error (exc );
116116 }
117117 requestObservation .stop ();
118- instrumentationState .restoreParentObservation (parameters .getGraphQLContext (), parentObservation );
119118 }
120119 };
121120 }
@@ -128,13 +127,8 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
128127 if (!parameters .isTrivialDataFetcher ()
129128 && state instanceof RequestObservationInstrumentationState instrumentationState ) {
130129 return (environment ) -> {
131- GraphQLContext graphQLContext = parameters .getExecutionContext ().getGraphQLContext ();
132- Observation parentObservation = graphQLContext .get (OBSERVATION_KEY );
133130 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 );
138132 dataFetcherObservation .start ();
139133 try {
140134 Object value = dataFetcher .get (environment );
@@ -145,20 +139,17 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
145139 dataFetcherObservation .error (error );
146140 }
147141 dataFetcherObservation .stop ();
148- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
149142 });
150143 }
151144 else {
152145 observationContext .setValue (value );
153146 dataFetcherObservation .stop ();
154- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
155147 return value ;
156148 }
157149 }
158150 catch (Throwable throwable ) {
159151 dataFetcherObservation .error (throwable );
160152 dataFetcherObservation .stop ();
161- instrumentationState .restoreParentObservation (graphQLContext , parentObservation );
162153 throw throwable ;
163154 }
164155 };
@@ -169,25 +160,28 @@ public DataFetcher<?> instrumentDataFetcher(DataFetcher<?> dataFetcher,
169160
170161 static class RequestObservationInstrumentationState implements InstrumentationState {
171162
163+ private Observation requestObservation ;
164+
165+ private final ConcurrentHashMap <ResultPath , Observation > activeObservations = new ConcurrentHashMap <>(8 );
166+
172167 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 ,
175170 DEFAULT_REQUEST_CONVENTION , () -> context , registry );
171+ this .requestObservation = observation ;
172+ return observation ;
176173 }
177174
178175 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 ,
181179 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 ;
191185 }
192186
193187 }
0 commit comments