Browse Source

Attaches error to Observation (#2743)

without this change when there is no response and the observation closing web exception handler stops the observation we've forgotten to attach an error to it
with this change we're attaching the error
pull/2745/head
Marcin Grzejszczak 2 years ago committed by GitHub
parent
commit
db35e58264
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java
  2. 1
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/GatewayContext.java
  3. 1
      spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservationClosingWebExceptionHandler.java
  4. 11
      spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/B3BraveObservedHttpHeadersFilterTests.java
  5. 4
      spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/ObservationClosingWebExceptionHandlerTests.java
  6. 21
      spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedHttpHeadersFilterTests.java

5
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/DefaultGatewayObservationConvention.java

@ -50,8 +50,9 @@ public class DefaultGatewayObservationConvention implements GatewayObservationCo
return keyValues; return keyValues;
} }
Route route = context.getServerWebExchange().getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); Route route = context.getServerWebExchange().getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
keyValues = keyValues.and(ROUTE_URI.withValue(route.getUri().toString()), keyValues = keyValues
METHOD.withValue(context.getRequest().getMethod().name())) .and(ROUTE_URI.withValue(route.getUri().toString()),
METHOD.withValue(context.getRequest().getMethod().name()))
.and(ROUTE_ID.withValue(route.getId())); .and(ROUTE_ID.withValue(route.getId()));
ServerHttpResponse response = context.getResponse(); ServerHttpResponse response = context.getResponse();
if (response != null && response.getStatusCode() != null) { if (response != null && response.getStatusCode() != null) {

1
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/GatewayContext.java

@ -53,4 +53,5 @@ public class GatewayContext extends RequestReplySenderContext<HttpHeaders, Serve
public ServerWebExchange getServerWebExchange() { public ServerWebExchange getServerWebExchange() {
return serverWebExchange; return serverWebExchange;
} }
} }

1
spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/headers/observation/ObservationClosingWebExceptionHandler.java

@ -41,6 +41,7 @@ public class ObservationClosingWebExceptionHandler implements WebExceptionHandle
Observation observation = exchange.getAttribute(ObservedRequestHttpHeadersFilter.CHILD_OBSERVATION); Observation observation = exchange.getAttribute(ObservedRequestHttpHeadersFilter.CHILD_OBSERVATION);
if (observation != null) { if (observation != null) {
log.debug(() -> "Observation was not previously stopped, will stop it."); log.debug(() -> "Observation was not previously stopped, will stop it.");
observation.error(ex);
observation.stop(); observation.stop();
} }
} }

11
spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/B3BraveObservedHttpHeadersFilterTests.java

@ -104,12 +104,11 @@ class B3BraveObservedHttpHeadersFilterTests {
assertThat(headers.get("b3").get(0)).matches("^" + context.traceId() + "-(.*)-1-" + context.spanId() + "$"); assertThat(headers.get("b3").get(0)).matches("^" + context.traceId() + "-(.*)-1-" + context.spanId() + "$");
List<FinishedSpan> finishedSpans = testSpanHandler.spans().stream().map(BraveFinishedSpan::new) List<FinishedSpan> finishedSpans = testSpanHandler.spans().stream().map(BraveFinishedSpan::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
SpansAssert.then(finishedSpans).hasASpanWithName("HTTP GET", spanAssert -> spanAssert SpansAssert.then(finishedSpans).hasASpanWithName("HTTP GET",
.hasTag("spring.cloud.gateway.route.id", "foo") spanAssert -> spanAssert.hasTag("spring.cloud.gateway.route.id", "foo").hasTag("http.method", "GET")
.hasTag("http.method", "GET") .hasTag("http.status_code", "200")
.hasTag("http.status_code", "200") .hasTag("spring.cloud.gateway.route.uri", "http://localhost:8080/")
.hasTag("spring.cloud.gateway.route.uri", "http://localhost:8080/") .hasTag("http.uri", "http://localhost:8080/get"));
.hasTag("http.uri", "http://localhost:8080/get"));
}); });
} }

4
spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/ObservationClosingWebExceptionHandlerTests.java

@ -52,8 +52,10 @@ class ObservationClosingWebExceptionHandlerTests {
void shouldStopTheObservationIfItWasNotStoppedPreviouslyAndThereWasAnError() { void shouldStopTheObservationIfItWasNotStoppedPreviouslyAndThereWasAnError() {
Observation observation = Mockito.mock(Observation.class); Observation observation = Mockito.mock(Observation.class);
exchange.getAttributes().put(ObservedRequestHttpHeadersFilter.CHILD_OBSERVATION, observation); exchange.getAttributes().put(ObservedRequestHttpHeadersFilter.CHILD_OBSERVATION, observation);
RuntimeException runtimeException = new RuntimeException();
assertThatNoException().isThrownBy(() -> handler.handle(exchange, new RuntimeException())); assertThatNoException().isThrownBy(() -> handler.handle(exchange, runtimeException));
Mockito.verify(observation).error(runtimeException);
Mockito.verify(observation).stop(); Mockito.verify(observation).stop();
} }

21
spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/headers/observation/ObservedHttpHeadersFilterTests.java

@ -84,17 +84,16 @@ public class ObservedHttpHeadersFilterTests extends SampleTestRunner {
.containsEntry("X-B3-TraceId", Collections.singletonList(context.traceId())) .containsEntry("X-B3-TraceId", Collections.singletonList(context.traceId()))
.doesNotContainEntry("X-B3-SpanId", Collections.singletonList(context.spanId())) .doesNotContainEntry("X-B3-SpanId", Collections.singletonList(context.spanId()))
.containsKey("X-B3-SpanId"); .containsKey("X-B3-SpanId");
SpansAssert.then(bb.getFinishedSpans()).hasASpanWithName("HTTP GET", spanAssert -> spanAssert SpansAssert.then(bb.getFinishedSpans()).hasASpanWithName("HTTP GET",
.hasTag("http.method", "GET").hasTag("http.status_code", "200") spanAssert -> spanAssert.hasTag("http.method", "GET").hasTag("http.status_code", "200")
.hasTag("http.uri", "http://localhost:8080/get") .hasTag("http.uri", "http://localhost:8080/get")
.hasTag("spring.cloud.gateway.route.uri", "http://localhost:8080/") .hasTag("spring.cloud.gateway.route.uri", "http://localhost:8080/")
.hasTag("spring.cloud.gateway.route.id", "foo")); .hasTag("spring.cloud.gateway.route.id", "foo"));
MeterRegistryAssert.then(meterRegistry) MeterRegistryAssert.then(meterRegistry).hasTimerWithNameAndTags("http.client.requests",
.hasTimerWithNameAndTags("http.client.requests", Tags.of("spring.cloud.gateway.route.id", "foo", "error", "none", "http.method", "GET",
Tags.of("spring.cloud.gateway.route.id", "foo", "error", "none", "http.method", "GET", "http.status_code", "200", "spring.cloud.gateway.route.uri", "http.status_code", "200", "spring.cloud.gateway.route.uri", "http://localhost:8080/"))
"http://localhost:8080/")) .hasMeterWithNameAndTags("http.client.requests.active", Tags.of("spring.cloud.gateway.route.id",
.hasMeterWithNameAndTags("http.client.requests.active", "foo", "http.method", "GET", "spring.cloud.gateway.route.uri", "http://localhost:8080/"));
Tags.of("spring.cloud.gateway.route.id", "foo", "http.method", "GET", "spring.cloud.gateway.route.uri", "http://localhost:8080/"));
}; };
} }

Loading…
Cancel
Save