Skip to content

Commit

Permalink
Configure GraphQL web propagation for tracing
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bclozel committed Dec 19, 2022
1 parent 5a973b9 commit 593b531
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
Expand Up @@ -19,6 +19,7 @@
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;
Expand All @@ -28,10 +29,15 @@
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
Expand All @@ -55,4 +61,19 @@ public GraphQlObservationInstrumentation graphQlObservationInstrumentation(Obser
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);
}

}

}
Expand Up @@ -18,6 +18,7 @@

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;
Expand All @@ -27,8 +28,11 @@
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}.
Expand Down Expand Up @@ -72,6 +76,24 @@ void instrumentationUsesCustomConventionsIfAvailable() {
});
}

@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 {

Expand Down Expand Up @@ -105,4 +127,22 @@ static class CustomDataFetcherObservationConvention extends DefaultDataFetcherOb

}

@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);
}
}

}

0 comments on commit 593b531

Please sign in to comment.