Skip to content

Commit

Permalink
Produce INTERNAL_ERROR observation outcome
Browse files Browse the repository at this point in the history
Prior to this commit, the `DefaultExecutionRequestObservationConvention`
would only produce "INTERNAL_ERROR" outcomes if the response is null or
if an unresolved exception remains.

The `ExceptionResolversExceptionHandler` will catch all unresolved
exceptions and add them to the errors map with the
`ErorType.INTERNAL_ERROR` error type. This means that the
"INTERNAL_ERROR" outcome is never used.

This commit ensures that this outcome is also used if at least one
resolved error is of `ErorType.INTERNAL_ERROR`.

Fixes gh-1065
  • Loading branch information
bclozel committed Oct 9, 2024
1 parent 5ffe512 commit b8b93a0
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
6 changes: 5 additions & 1 deletion spring-graphql-docs/modules/ROOT/pages/observability.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ By default, the following KeyValues are created:
|===

The `graphql.operation` KeyValue will use the custom name of the provided query, or http://spec.graphql.org/draft/#sec-Language.Operations[the standard name for the operation] if none (`"query"`, `"mutation"` or `"subscription"`).
The `graphql.outcome` KeyValue will be `"SUCCESS"` if a valid GraphQL response has been sent, `"REQUEST_ERROR"` if the request could not be parsed, or `"INTERNAL_ERROR"` if no valid GraphQL response could be produced.
The `graphql.outcome` KeyValue will be:

* `"SUCCESS"` if a valid GraphQL response has been sent and it contains no errors
* `"REQUEST_ERROR"` if the request could not be parsed, or if the response contains errors (none of them being of type `org.springframework.graphql.execution.ErrorType.INTERNAL_ERROR`)
* `"INTERNAL_ERROR"` if no valid GraphQL response could be produced, or if the response contains at least one error of type `org.springframework.graphql.execution.ErrorType.INTERNAL_ERROR`

.High cardinality Keys
[cols="a,a"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;

import org.springframework.graphql.execution.ErrorType;
import org.springframework.graphql.observation.GraphQlObservationDocumentation.ExecutionRequestHighCardinalityKeyNames;
import org.springframework.graphql.observation.GraphQlObservationDocumentation.ExecutionRequestLowCardinalityKeyNames;

Expand Down Expand Up @@ -73,7 +74,10 @@ protected KeyValue outcome(ExecutionRequestObservationContext context) {
if (context.getError() != null || context.getExecutionResult() == null) {
return OUTCOME_INTERNAL_ERROR;
}
else if (context.getExecutionResult().getErrors().size() > 0) {
else if (!context.getExecutionResult().getErrors().isEmpty()) {
if (context.getExecutionResult().getErrors().stream().anyMatch((error) -> ErrorType.INTERNAL_ERROR.equals(error.getErrorType()))) {
return OUTCOME_INTERNAL_ERROR;
}
return OUTCOME_REQUEST_ERROR;
}
return OUTCOME_SUCCESS;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 the original author or authors.
* Copyright 2020-2024 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.
Expand All @@ -19,12 +19,16 @@
import java.util.function.Consumer;

import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLError;
import graphql.execution.ExecutionId;
import graphql.schema.idl.errors.QueryOperationMissingError;
import io.micrometer.common.KeyValue;
import org.junit.jupiter.api.Test;

import org.springframework.graphql.execution.ErrorType;

import static org.assertj.core.api.Assertions.assertThat;

/**
Expand Down Expand Up @@ -86,7 +90,8 @@ void hasOutcomeKeyValueWhenErrorOutput() {
void hasOutcomeKeyValueWhenInternalError() {
ExecutionRequestObservationContext context = createObservationContext(this.input, builder -> {
});
context.setError(new IllegalStateException("custom internal error"));
GraphQLError graphQLError = GraphQLError.newError().errorType(ErrorType.INTERNAL_ERROR).message(ErrorType.INTERNAL_ERROR + " for [executionId]").build();
context.setExecutionResult(ExecutionResult.newExecutionResult().addError(graphQLError).build());
assertThat(this.convention.getLowCardinalityKeyValues(context)).contains(KeyValue.of("graphql.outcome", "INTERNAL_ERROR"));
}

Expand Down

0 comments on commit b8b93a0

Please sign in to comment.