Configure GraphQL web propagation for tracing
As of spring-projects/spring-graphql#547, Spring GraphQL introduced a `PropagationWebGraphQlInterceptor` that propagates the incoming tracing information in HTTP request headers into the GraphQL context. This commit auto-configures the propagation interceptor if the application exposes a GraphQL HTTP endpoint and if it is configured for Tracing support. Fixes gh-33542
This commit is contained in:
@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.observation.graphql;
|
||||
import graphql.GraphQL;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.propagation.Propagator;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration;
|
||||
@@ -28,10 +29,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.observation.DataFetcherObservationConvention;
|
||||
import org.springframework.graphql.observation.ExecutionRequestObservationConvention;
|
||||
import org.springframework.graphql.observation.GraphQlObservationInstrumentation;
|
||||
import org.springframework.graphql.observation.PropagationWebGraphQlInterceptor;
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring
|
||||
@@ -55,4 +61,19 @@ public class GraphQlObservationAutoConfiguration {
|
||||
dataFetcherConvention.getIfAvailable());
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Propagator.class)
|
||||
@ConditionalOnBean(WebGraphQlHandler.class)
|
||||
static class TracingObservationConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(Propagator.class)
|
||||
@ConditionalOnMissingBean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
||||
public PropagationWebGraphQlInterceptor propagationWebGraphQlInterceptor(Propagator propagator) {
|
||||
return new PropagationWebGraphQlInterceptor(propagator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.observation.graphql;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import io.micrometer.tracing.propagation.Propagator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -27,8 +28,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.observation.DefaultDataFetcherObservationConvention;
|
||||
import org.springframework.graphql.observation.DefaultExecutionRequestObservationConvention;
|
||||
import org.springframework.graphql.observation.GraphQlObservationInstrumentation;
|
||||
import org.springframework.graphql.observation.PropagationWebGraphQlInterceptor;
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlObservationAutoConfiguration}.
|
||||
@@ -72,6 +76,24 @@ class GraphQlObservationAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void propagationInterceptorNotContributedWhenPropagatorIsMissing() {
|
||||
this.contextRunner.withUserConfiguration(WebGraphQlConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PropagationWebGraphQlInterceptor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void propagationInterceptorNotContributedWhenNotWebApplication() {
|
||||
this.contextRunner.withUserConfiguration(TracingConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(PropagationWebGraphQlInterceptor.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void propagationInterceptorContributed() {
|
||||
this.contextRunner.withUserConfiguration(WebGraphQlConfiguration.class, TracingConfiguration.class)
|
||||
.run((context) -> assertThat(context).hasSingleBean(PropagationWebGraphQlInterceptor.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class InstrumentationConfiguration {
|
||||
|
||||
@@ -105,4 +127,22 @@ class GraphQlObservationAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class WebGraphQlConfiguration {
|
||||
|
||||
@Bean
|
||||
WebGraphQlHandler webGraphQlHandler() {
|
||||
return mock(WebGraphQlHandler.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TracingConfiguration {
|
||||
|
||||
@Bean
|
||||
Propagator propagator() {
|
||||
return mock(Propagator.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user