Merge branch '1.1.x'
This commit is contained in:
@@ -13,7 +13,11 @@ If your application is using Spring Boot, contributing the custom convention as
|
||||
[[observability.server.request]]
|
||||
== Server Requests instrumentation
|
||||
|
||||
GraphQL Server Requests observations are created with the name `"graphql.request"` for Servlet and Reactive applications and above all supported transports.
|
||||
GraphQL Server Requests observations are created with the name `"graphql.request"` for traditional and Reactive applications and above all supported transports.
|
||||
This instrumentation assumes that any parent observation must be set as the current one on the GraphQL context with the well-known `"micrometer.observation"` key.
|
||||
For trace propagation across network boundaries, a separate instrumentation at the transport level must be in charge.
|
||||
In the case of HTTP, Spring Framework {spring-framework-ref-docs}/integration.html#integration.observability.http-server[has dedicated instrumentation that takes care of trace propagation].
|
||||
|
||||
Applications need to configure the `org.springframework.graphql.observation.GraphQlObservationInstrumentation` instrumentation in their application.
|
||||
It is using the `org.springframework.graphql.observation.DefaultExecutionRequestObservationConvention` by default, backed by the `ExecutionRequestObservationContext`.
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -60,7 +60,7 @@ public class DefaultExecutionRequestObservationConvention implements ExecutionRe
|
||||
|
||||
@Override
|
||||
public String getContextualName(ExecutionRequestObservationContext context) {
|
||||
String operationName = (context.getCarrier().getOperationName() != null) ? context.getCarrier().getOperationName() : "query";
|
||||
String operationName = (context.getExecutionInput().getOperationName() != null) ? context.getExecutionInput().getOperationName() : "query";
|
||||
return BASE_CONTEXTUAL_NAME + operationName;
|
||||
}
|
||||
|
||||
@@ -70,17 +70,17 @@ public class DefaultExecutionRequestObservationConvention implements ExecutionRe
|
||||
}
|
||||
|
||||
protected KeyValue outcome(ExecutionRequestObservationContext context) {
|
||||
if (context.getError() != null || context.getResponse() == null) {
|
||||
if (context.getError() != null || context.getExecutionResult() == null) {
|
||||
return OUTCOME_INTERNAL_ERROR;
|
||||
}
|
||||
else if (context.getResponse().getErrors().size() > 0) {
|
||||
else if (context.getExecutionResult().getErrors().size() > 0) {
|
||||
return OUTCOME_REQUEST_ERROR;
|
||||
}
|
||||
return OUTCOME_SUCCESS;
|
||||
}
|
||||
|
||||
protected KeyValue operation(ExecutionRequestObservationContext context) {
|
||||
String operationName = context.getCarrier().getOperationName();
|
||||
String operationName = context.getExecutionInput().getOperationName();
|
||||
if (operationName != null) {
|
||||
return KeyValue.of(ExecutionRequestLowCardinalityKeyNames.OPERATION, operationName);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class DefaultExecutionRequestObservationConvention implements ExecutionRe
|
||||
}
|
||||
|
||||
protected KeyValue executionId(ExecutionRequestObservationContext context) {
|
||||
return KeyValue.of(ExecutionRequestHighCardinalityKeyNames.EXECUTION_ID, context.getCarrier().getExecutionId().toString());
|
||||
return KeyValue.of(ExecutionRequestHighCardinalityKeyNames.EXECUTION_ID, context.getExecutionInput().getExecutionId().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -16,42 +16,72 @@
|
||||
|
||||
package org.springframework.graphql.observation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.ExecutionResult;
|
||||
import io.micrometer.observation.transport.RequestReplyReceiverContext;
|
||||
import io.micrometer.observation.Observation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Context that holds information for metadata collection during observations
|
||||
* for {@link GraphQlObservationDocumentation#EXECUTION_REQUEST GraphQL requests}.
|
||||
* <p>This context also extends {@link RequestReplyReceiverContext} for propagating
|
||||
* tracing information from the {@link graphql.GraphQLContext}
|
||||
* or the {@link ExecutionInput#getExtensions() input extensions}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class ExecutionRequestObservationContext extends RequestReplyReceiverContext<ExecutionInput, ExecutionResult> {
|
||||
public class ExecutionRequestObservationContext extends Observation.Context {
|
||||
|
||||
public ExecutionRequestObservationContext(ExecutionInput executionInput) {
|
||||
super(ExecutionRequestObservationContext::getContextValue);
|
||||
setCarrier(executionInput);
|
||||
}
|
||||
private final ExecutionInput executionInput;
|
||||
|
||||
/**
|
||||
* Read propagation field from the {@link graphql.GraphQLContext},
|
||||
* or the {@link ExecutionInput#getExtensions() input extensions} as a fallback.
|
||||
*/
|
||||
private static String getContextValue(ExecutionInput executionInput, String key) {
|
||||
String value = executionInput.getGraphQLContext().get(key);
|
||||
if (value == null) {
|
||||
Map<String, Object> extensions = executionInput.getExtensions();
|
||||
if (extensions != null) {
|
||||
value = (String) extensions.get(key);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@Nullable
|
||||
private ExecutionResult executionResult;
|
||||
|
||||
public ExecutionRequestObservationContext(ExecutionInput executionInput) {
|
||||
this.executionInput = executionInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ExecutionInput input} for the request execution.
|
||||
* @since 1.1.4
|
||||
*/
|
||||
public ExecutionInput getExecutionInput() {
|
||||
return this.executionInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ExecutionInput input} for the request execution.
|
||||
* @deprecated since 1.1.4 in favor of {@link #getExecutionInput()}
|
||||
*/
|
||||
@Deprecated(since = "1.1.4", forRemoval = true)
|
||||
public ExecutionInput getCarrier() {
|
||||
return this.executionInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ExecutionResult result} for the request execution.
|
||||
* @since 1.1.4
|
||||
*/
|
||||
@Nullable
|
||||
public ExecutionResult getExecutionResult() {
|
||||
return this.executionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ExecutionResult result} for the request execution.
|
||||
* @param executionResult the execution result
|
||||
* @since 1.1.4
|
||||
*/
|
||||
public void setExecutionResult(ExecutionResult executionResult) {
|
||||
this.executionResult = executionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ExecutionResult result} for the request execution.
|
||||
* @deprecated since 1.1.4 in favor of {@link #getExecutionResult()}
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated(since = "1.1.4", forRemoval = true)
|
||||
public ExecutionResult getResponse() {
|
||||
return this.executionResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
|
||||
package org.springframework.graphql.observation;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLContext;
|
||||
import graphql.execution.ExecutionStepInfo;
|
||||
import graphql.execution.ResultPath;
|
||||
import graphql.execution.instrumentation.InstrumentationContext;
|
||||
import graphql.execution.instrumentation.InstrumentationState;
|
||||
import graphql.execution.instrumentation.SimpleInstrumentationContext;
|
||||
@@ -30,6 +29,10 @@ import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchPar
|
||||
import graphql.schema.DataFetcher;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* {@link graphql.execution.instrumentation.Instrumentation} that creates
|
||||
@@ -50,8 +53,6 @@ import io.micrometer.observation.ObservationRegistry;
|
||||
*/
|
||||
public class GraphQlObservationInstrumentation extends SimplePerformantInstrumentation {
|
||||
|
||||
private static final String OBSERVATION_KEY = "micrometer.observation";
|
||||
|
||||
private static final ExecutionRequestObservationConvention DEFAULT_REQUEST_CONVENTION =
|
||||
new DefaultExecutionRequestObservationConvention();
|
||||
|
||||
@@ -101,21 +102,19 @@ 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 parentObservation = parameters.getGraphQLContext().get(ObservationThreadLocalAccessor.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);
|
||||
observationContext.setExecutionResult(result);
|
||||
if (exc != null) {
|
||||
requestObservation.error(exc);
|
||||
}
|
||||
requestObservation.stop();
|
||||
instrumentationState.restoreParentObservation(parameters.getGraphQLContext(), parentObservation);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -128,13 +127,8 @@ 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);
|
||||
dataFetcherObservation.parentObservation(parentObservation);
|
||||
graphQLContext.put(OBSERVATION_KEY, dataFetcherObservation);
|
||||
Observation dataFetcherObservation = instrumentationState.createDataFetcherObservation(this.dataFetcherObservationConvention, observationContext, this.observationRegistry);
|
||||
dataFetcherObservation.start();
|
||||
try {
|
||||
Object value = dataFetcher.get(environment);
|
||||
@@ -145,20 +139,17 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen
|
||||
dataFetcherObservation.error(error);
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
@@ -169,25 +160,28 @@ public class GraphQlObservationInstrumentation extends SimplePerformantInstrumen
|
||||
|
||||
static class RequestObservationInstrumentationState implements InstrumentationState {
|
||||
|
||||
private Observation requestObservation;
|
||||
|
||||
private final ConcurrentHashMap<ResultPath, Observation> activeObservations = new ConcurrentHashMap<>(8);
|
||||
|
||||
Observation createRequestObservation(ExecutionRequestObservationConvention convention,
|
||||
ExecutionRequestObservationContext context, ObservationRegistry registry) {
|
||||
return GraphQlObservationDocumentation.EXECUTION_REQUEST.observation(convention,
|
||||
ExecutionRequestObservationContext context, ObservationRegistry registry) {
|
||||
Observation observation = GraphQlObservationDocumentation.EXECUTION_REQUEST.observation(convention,
|
||||
DEFAULT_REQUEST_CONVENTION, () -> context, registry);
|
||||
this.requestObservation = observation;
|
||||
return observation;
|
||||
}
|
||||
|
||||
Observation createDataFetcherObservation(DataFetcherObservationConvention convention,
|
||||
DataFetcherObservationContext context, ObservationRegistry registry) {
|
||||
return GraphQlObservationDocumentation.DATA_FETCHER.observation(convention,
|
||||
DataFetcherObservationContext context, ObservationRegistry registry) {
|
||||
ExecutionStepInfo executionStepInfo = context.getEnvironment().getExecutionStepInfo();
|
||||
Observation observation = GraphQlObservationDocumentation.DATA_FETCHER.observation(convention,
|
||||
DEFAULT_DATA_FETCHER_CONVENTION, () -> context, registry);
|
||||
}
|
||||
|
||||
void restoreParentObservation(GraphQLContext context, Observation parentObservation) {
|
||||
if (parentObservation != null) {
|
||||
context.put(OBSERVATION_KEY, parentObservation);
|
||||
}
|
||||
else {
|
||||
context.delete(OBSERVATION_KEY);
|
||||
}
|
||||
Observation parentObservation = (executionStepInfo.hasParent()) ? this.activeObservations.getOrDefault(executionStepInfo.getParent().getPath(), this.requestObservation)
|
||||
: this.requestObservation;
|
||||
observation.parentObservation(parentObservation);
|
||||
this.activeObservations.put(executionStepInfo.getPath(), observation);
|
||||
return observation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 1.1.1
|
||||
* @deprecated since 1.1.4 with no replacement.
|
||||
*/
|
||||
@Deprecated(since = "1.1.4", forRemoval = true)
|
||||
public class PropagationWebGraphQlInterceptor implements WebGraphQlInterceptor {
|
||||
|
||||
private final Propagator propagator;
|
||||
|
||||
@@ -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.
|
||||
@@ -102,7 +102,7 @@ class DefaultExecutionRequestObservationConventionTests {
|
||||
ExecutionRequestObservationContext context = new ExecutionRequestObservationContext(executionInput);
|
||||
ExecutionResultImpl.Builder builder = ExecutionResultImpl.newExecutionResult();
|
||||
resultConsumer.accept(builder);
|
||||
context.setResponse(builder.build());
|
||||
context.setExecutionResult(builder.build());
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.graphql.observation;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ExecutionRequestObservationContext}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class ExecutionRequestObservationContextTests {
|
||||
|
||||
@Test
|
||||
void readPropagationFieldFromGraphQlContext() {
|
||||
ExecutionInput executionInput = ExecutionInput
|
||||
.newExecutionInput("{ notUsed }")
|
||||
.graphQLContext(builder -> builder.of("X-Tracing-Test", "traceId"))
|
||||
.build();
|
||||
ExecutionRequestObservationContext context = new ExecutionRequestObservationContext(executionInput);
|
||||
assertThat(context.getGetter().get(executionInput, "X-Tracing-Test")).isEqualTo("traceId");
|
||||
}
|
||||
|
||||
@Test
|
||||
void readPropagationFieldFromExtensions() {
|
||||
ExecutionInput executionInput = ExecutionInput
|
||||
.newExecutionInput("{ notUsed }")
|
||||
.extensions(Map.of("X-Tracing-Test", "traceId"))
|
||||
.build();
|
||||
ExecutionRequestObservationContext context = new ExecutionRequestObservationContext(executionInput);
|
||||
assertThat(context.getGetter().get(executionInput, "X-Tracing-Test")).isEqualTo("traceId");
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotFailIsMissingPropagationField() {
|
||||
ExecutionInput executionInput = ExecutionInput
|
||||
.newExecutionInput("{ notUsed }")
|
||||
.build();
|
||||
ExecutionRequestObservationContext context = new ExecutionRequestObservationContext(executionInput);
|
||||
assertThat(context.getGetter().get(executionInput, "X-Tracing-Test")).isNull();
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,12 @@
|
||||
|
||||
package org.springframework.graphql.observation;
|
||||
|
||||
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.contextpropagation.ObservationThreadLocalAccessor;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import io.micrometer.observation.tck.TestObservationRegistryAssert;
|
||||
import io.micrometer.observation.transport.ReceiverContext;
|
||||
import io.micrometer.tracing.Span;
|
||||
import io.micrometer.tracing.TraceContext;
|
||||
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
|
||||
import io.micrometer.tracing.handler.TracingObservationHandler;
|
||||
import io.micrometer.tracing.propagation.Propagator;
|
||||
import io.micrometer.tracing.test.simple.SimpleSpanBuilder;
|
||||
import io.micrometer.tracing.test.simple.SimpleTracer;
|
||||
import io.micrometer.tracing.test.simple.TracerAssert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -45,7 +34,7 @@ import org.springframework.graphql.TestExecutionRequest;
|
||||
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlObservationInstrumentation}.
|
||||
@@ -134,7 +123,8 @@ class GraphQlObservationInstrumentationTests {
|
||||
.that()
|
||||
.hasLowCardinalityKeyValue("graphql.outcome", "SUCCESS")
|
||||
.hasLowCardinalityKeyValue("graphql.field.name", "bookById")
|
||||
.hasHighCardinalityKeyValue("graphql.field.path", "/bookById");
|
||||
.hasHighCardinalityKeyValue("graphql.field.path", "/bookById")
|
||||
.hasParentObservationContextMatching(context -> context instanceof ExecutionRequestObservationContext);
|
||||
|
||||
TestObservationRegistryAssert.assertThat(this.observationRegistry)
|
||||
.hasAnObservationWithAKeyValue("graphql.field.name", "author")
|
||||
@@ -213,7 +203,7 @@ class GraphQlObservationInstrumentationTests {
|
||||
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());
|
||||
builder.graphQLContext(contextBuilder -> contextBuilder.of(ObservationThreadLocalAccessor.KEY, incoming)).build());
|
||||
Mono<ExecutionGraphQlResponse> responseMono = graphQlSetup
|
||||
.queryFetcher("bookById", env -> BookSource.getBookWithoutAuthor(1L))
|
||||
.toGraphQlService()
|
||||
@@ -225,65 +215,4 @@ class GraphQlObservationInstrumentationTests {
|
||||
incoming.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void inboundTracingInformationIsPropagated() {
|
||||
SimpleTracer simpleTracer = new SimpleTracer();
|
||||
String traceId = "traceId";
|
||||
TracingObservationHandler<ReceiverContext> tracingHandler = new PropagatingReceiverTracingObservationHandler<>(simpleTracer, new TestPropagator(simpleTracer, traceId));
|
||||
this.observationRegistry.observationConfig().observationHandler(tracingHandler);
|
||||
String document = """
|
||||
{
|
||||
bookById(id: 1) {
|
||||
name
|
||||
}
|
||||
}
|
||||
""";
|
||||
ExecutionGraphQlRequest executionRequest = TestExecutionRequest.forDocument(document);
|
||||
executionRequest.configureExecutionInput((input, builder) ->
|
||||
builder.graphQLContext(context -> context.of(TestPropagator.TRACING_HEADER_NAME, traceId)).build());
|
||||
Mono<ExecutionGraphQlResponse> responseMono = graphQlSetup
|
||||
.queryFetcher("bookById", env -> BookSource.getBookWithoutAuthor(1L))
|
||||
.toGraphQlService()
|
||||
.execute(executionRequest);
|
||||
ResponseHelper response = ResponseHelper.forResponse(responseMono);
|
||||
|
||||
TracerAssert.assertThat(simpleTracer)
|
||||
.onlySpan()
|
||||
.hasNameEqualTo("graphql query")
|
||||
.hasKindEqualTo(Span.Kind.SERVER)
|
||||
.hasTag("graphql.operation", "query")
|
||||
.hasTag("graphql.outcome", "SUCCESS")
|
||||
.hasTagWithKey("graphql.execution.id");
|
||||
}
|
||||
|
||||
static class TestPropagator implements Propagator {
|
||||
|
||||
public static String TRACING_HEADER_NAME = "X-Test-Tracing";
|
||||
|
||||
private final SimpleTracer tracer;
|
||||
|
||||
private final String traceId;
|
||||
|
||||
TestPropagator(SimpleTracer tracer, String traceId) {
|
||||
this.tracer = tracer;
|
||||
this.traceId = traceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> fields() {
|
||||
return List.of(TRACING_HEADER_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void inject(TraceContext context, C carrier, Setter<C> setter) {
|
||||
setter.set(carrier, TRACING_HEADER_NAME, "traceId");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> Span.Builder extract(C carrier, Getter<C> getter) {
|
||||
String foo = getter.get(carrier, TRACING_HEADER_NAME);
|
||||
assertThat(foo).isEqualTo(this.traceId);
|
||||
return new SimpleSpanBuilder(this.tracer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
class PropagationWebGraphQlInterceptorTests {
|
||||
|
||||
PropagationWebGraphQlInterceptor interceptor = new PropagationWebGraphQlInterceptor(new TestPropagator());
|
||||
|
||||
Reference in New Issue
Block a user