Merge branch '1.1.x'

This commit is contained in:
Brian Clozel
2023-02-14 16:08:13 +01:00
4 changed files with 61 additions and 25 deletions

View File

@@ -2,7 +2,7 @@ description = "Spring for GraphQL"
ext {
moduleProjects = [project(":spring-graphql"), project(":spring-graphql-test")]
springFrameworkVersion = "6.0.3"
springFrameworkVersion = "6.0.4"
graphQlJavaVersion = "20.0"
springBootVersion = "3.0.0"
}

View File

@@ -8,11 +8,11 @@ javaPlatform {
dependencies {
api(platform("org.springframework:spring-framework-bom:${springFrameworkVersion}"))
api(platform("com.fasterxml.jackson:jackson-bom:2.14.1"))
api(platform("io.projectreactor:reactor-bom:2022.0.1"))
api(platform("io.micrometer:micrometer-bom:1.10.2"))
api(platform("io.micrometer:micrometer-tracing-bom:1.0.0"))
api(platform("org.springframework.data:spring-data-bom:2022.0.0"))
api(platform("com.fasterxml.jackson:jackson-bom:2.14.2"))
api(platform("io.projectreactor:reactor-bom:2022.0.2"))
api(platform("io.micrometer:micrometer-bom:1.10.4"))
api(platform("io.micrometer:micrometer-tracing-bom:1.0.2"))
api(platform("org.springframework.data:spring-data-bom:2022.0.1"))
api(platform("org.springframework.security:spring-security-bom:6.0.1"))
api(platform("com.querydsl:querydsl-bom:5.0.0"))
api(platform("io.rsocket:rsocket-bom:1.1.3"))
@@ -25,7 +25,7 @@ dependencies {
constraints {
api("com.graphql-java:graphql-java:${graphQlJavaVersion}")
api("io.micrometer:context-propagation:1.0.0")
api("io.micrometer:context-propagation:1.0.2")
api("jakarta.annotation:jakarta.annotation-api:2.1.1")
api("jakarta.servlet:jakarta.servlet-api:6.0.0")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2022 the original author or authors.
* Copyright 2020-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.graphql.observation;
import java.util.concurrent.CompletionStage;
import graphql.ExecutionResult;
import graphql.GraphQLContext;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.InstrumentationState;
import graphql.execution.instrumentation.SimpleInstrumentationContext;
@@ -100,20 +101,21 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen
InstrumentationState state) {
if (state instanceof RequestObservationInstrumentationState instrumentationState) {
ExecutionRequestObservationContext observationContext = new ExecutionRequestObservationContext(parameters.getExecutionInput());
Observation parentObservation = parameters.getGraphQLContext().get(OBSERVATION_KEY);
Observation requestObservation = instrumentationState.createRequestObservation(this.requestObservationConvention,
observationContext, this.observationRegistry);
requestObservation.parentObservation(parentObservation);
parameters.getGraphQLContext().put(OBSERVATION_KEY, requestObservation);
requestObservation.start();
return new SimpleInstrumentationContext<>() {
@Override
public void onCompleted(ExecutionResult result, Throwable exc) {
observationContext.setResponse(result);
if (exc != null) {
observationContext.setError(exc);
requestObservation.error(exc);
}
else {
requestObservation.stop();
}
requestObservation.stop();
instrumentationState.restoreParentObservation(parameters.getGraphQLContext(), parentObservation);
}
};
}
@@ -126,58 +128,66 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen
if (!parameters.isTrivialDataFetcher()
&& state instanceof RequestObservationInstrumentationState instrumentationState) {
return (environment) -> {
GraphQLContext graphQLContext = parameters.getExecutionContext().getGraphQLContext();
Observation parentObservation = graphQLContext.get(OBSERVATION_KEY);
DataFetcherObservationContext observationContext = new DataFetcherObservationContext(parameters.getEnvironment());
Observation dataFetcherObservation = instrumentationState.createDataFetcherObservation(
this.dataFetcherObservationConvention, observationContext, this.observationRegistry);
parameters.getExecutionContext().getGraphQLContext().put(OBSERVATION_KEY, dataFetcherObservation);
dataFetcherObservation.parentObservation(parentObservation);
graphQLContext.put(OBSERVATION_KEY, dataFetcherObservation);
dataFetcherObservation.start();
try {
Object value = dataFetcher.get(environment);
if (value instanceof CompletionStage<?> completion) {
return completion.whenComplete((result, error) -> {
observationContext.setValue(result);
if (error != null) {
dataFetcherObservation.error(error);
}
observationContext.setValue(result);
dataFetcherObservation.stop();
instrumentationState.restoreParentObservation(graphQLContext, parentObservation);
});
}
else {
observationContext.setValue(value);
dataFetcherObservation.stop();
instrumentationState.restoreParentObservation(graphQLContext, parentObservation);
return value;
}
}
catch (Throwable throwable) {
dataFetcherObservation.error(throwable);
dataFetcherObservation.stop();
instrumentationState.restoreParentObservation(graphQLContext, parentObservation);
throw throwable;
}
};
}
return super.instrumentDataFetcher(dataFetcher, parameters, state);
return dataFetcher;
}
static class RequestObservationInstrumentationState implements InstrumentationState {
private Observation requestObservation;
Observation createRequestObservation(ExecutionRequestObservationConvention convention,
ExecutionRequestObservationContext context, ObservationRegistry registry) {
Observation observation = GraphQlObservationDocumentation.EXECUTION_REQUEST.observation(convention,
return GraphQlObservationDocumentation.EXECUTION_REQUEST.observation(convention,
DEFAULT_REQUEST_CONVENTION, () -> context, registry);
this.requestObservation = observation;
return observation;
}
Observation createDataFetcherObservation(DataFetcherObservationConvention convention,
DataFetcherObservationContext context, ObservationRegistry registry) {
Observation dataFetcherObservation = GraphQlObservationDocumentation.DATA_FETCHER.observation(convention,
return GraphQlObservationDocumentation.DATA_FETCHER.observation(convention,
DEFAULT_DATA_FETCHER_CONVENTION, () -> context, registry);
dataFetcherObservation.parentObservation(requestObservation);
return dataFetcherObservation;
}
void restoreParentObservation(GraphQLContext context, Observation parentObservation) {
if (parentObservation != null) {
context.put(OBSERVATION_KEY, parentObservation);
}
else {
context.delete(OBSERVATION_KEY);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020-2022 the original author or authors.
* Copyright 2020-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
import graphql.GraphqlErrorBuilder;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistry;
import io.micrometer.observation.tck.TestObservationRegistryAssert;
import io.micrometer.observation.transport.ReceiverContext;
@@ -199,6 +201,30 @@ class GraphQlObservationInstrumentationTests {
.hasParentObservationContextMatching(context -> context instanceof ExecutionRequestObservationContext);
}
@Test
void setIncomingObservationAsParent() {
String document = """
{
bookById(id: 1) {
name
}
}
""";
ExecutionGraphQlRequest graphQlRequest = TestExecutionRequest.forDocument(document);
Observation incoming = Observation.start("incoming", ObservationRegistry.create());
graphQlRequest.configureExecutionInput((input, builder) ->
builder.graphQLContext(contextBuilder -> contextBuilder.of("micrometer.observation", incoming)).build());
Mono<ExecutionGraphQlResponse> responseMono = graphQlSetup
.queryFetcher("bookById", env -> BookSource.getBookWithoutAuthor(1L))
.toGraphQlService()
.execute(graphQlRequest);
ResponseHelper response = ResponseHelper.forResponse(responseMono);
TestObservationRegistryAssert.assertThat(this.observationRegistry).hasObservationWithNameEqualTo("graphql.request")
.that().hasParentObservationEqualTo(incoming);
incoming.stop();
}
@Test
void inboundTracingInformationIsPropagated() {
SimpleTracer simpleTracer = new SimpleTracer();