Add HttpOutcome for HTTP observations

Prior to this commit, the HTTP Observations would use
`HttpStatus.Series` as a value source for the "outcome" key value in
recorded observations. This would work for most cases, but would not
align in the 2xx HTTP status cases: the series would provide a
"SUCESSFUL" value whereas the heritage metrics support in Spring Boot
would give "SUCESS".

This commit introduces a dedicated `HttpOutcome` concept for this and
applies it to all HTTP observations.

Fixes gh-29232
This commit is contained in:
Brian Clozel
2022-09-30 18:14:10 +02:00
parent b9070ae752
commit 8c24e8c034
15 changed files with 224 additions and 42 deletions

View File

@@ -22,7 +22,7 @@ import io.micrometer.common.KeyValue;
import io.micrometer.common.KeyValues;
import io.micrometer.observation.ObservationConvention;
import org.springframework.http.HttpStatus;
import org.springframework.http.observation.HttpOutcome;
import org.springframework.util.StringUtils;
/**
@@ -42,7 +42,6 @@ public class DefaultClientObservationConvention implements ClientObservationConv
private static final KeyValue EXCEPTION_NONE = KeyValue.of(ClientObservation.LowCardinalityKeyNames.EXCEPTION, "none");
private static final KeyValue OUTCOME_UNKNOWN = KeyValue.of(ClientObservation.LowCardinalityKeyNames.OUTCOME, "UNKNOWN");
private final String name;
@@ -117,15 +116,13 @@ public class DefaultClientObservationConvention implements ClientObservationConv
protected static KeyValue outcome(ClientObservationContext context) {
if (context.isAborted()) {
return OUTCOME_UNKNOWN;
return HttpOutcome.UNKNOWN.asKeyValue();
}
else if (context.getResponse() != null) {
HttpStatus status = HttpStatus.resolve(context.getResponse().statusCode().value());
if (status != null) {
return KeyValue.of(ClientObservation.LowCardinalityKeyNames.OUTCOME, status.series().name());
}
HttpOutcome httpOutcome = HttpOutcome.forStatus(context.getResponse().statusCode());
return httpOutcome.asKeyValue();
}
return OUTCOME_UNKNOWN;
return HttpOutcome.UNKNOWN.asKeyValue();
}
@Override

View File

@@ -83,7 +83,7 @@ class DefaultClientObservationConventionTests {
context.setUriTemplate("/resource/{id}");
assertThat(this.observationConvention.getLowCardinalityKeyValues(context))
.contains(KeyValue.of("exception", "none"), KeyValue.of("method", "GET"), KeyValue.of("uri", "/resource/{id}"),
KeyValue.of("status", "200"), KeyValue.of("outcome", "SUCCESSFUL"));
KeyValue.of("status", "200"), KeyValue.of("outcome", "SUCCESS"));
assertThat(this.observationConvention.getHighCardinalityKeyValues(context)).hasSize(2)
.contains(KeyValue.of("client.name", "none"), KeyValue.of("uri.expanded", "/resource/42"));
}

View File

@@ -66,7 +66,7 @@ public class DefaultClientObservationTests {
.retrieve().bodyToMono(Void.class).block(Duration.ofSeconds(10));
verifyAndGetRequest();
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESSFUL")
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS")
.hasLowCardinalityKeyValue("uri", "/resource/{id}");
}