From 97e5e32496a29410f93ff40566780aeac26e3eef Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 3 Nov 2016 20:08:31 +0000 Subject: [PATCH] Make sure the MetricsFilter uses committed response's status Previously, if an exception was thrown during request handling after the response had been committed, i.e. after the status and headers had been written, the metrics filter would assume that it was a 500 response. This was potentially inaccurate as the status had already been sent to the client and before the exception was thrown and it may have been something other than a 500. This commit updates MetricsFilter so that it will use the status from the response if the response has been committed even when an exception is thrown. Closes gh-7277 --- .../actuate/autoconfigure/MetricsFilter.java | 3 ++ .../MetricFilterAutoConfigurationTests.java | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java index c011237aeea..cfcd6fc1098 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/MetricsFilter.java @@ -109,6 +109,9 @@ final class MetricsFilter extends OncePerRequestFilter { } finally { if (!request.isAsyncStarted()) { + if (response.isCommitted()) { + status = getStatus(response); + } stopWatch.stop(); request.removeAttribute(ATTRIBUTE_STOP_WATCH); recordMetrics(request, path, status, stopWatch.getTotalTimeMillis()); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java index 73f90a53326..62b3aa1bb7f 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/MetricFilterAutoConfigurationTests.java @@ -365,6 +365,37 @@ public class MetricFilterAutoConfigurationTests { context.close(); } + @Test + public void whenExceptionIsThrownResponseStatusIsUsedWhenResponseHasBeenCommitted() + throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(Config.class, MetricFilterAutoConfiguration.class); + context.refresh(); + Filter filter = context.getBean(Filter.class); + final MockHttpServletRequest request = new MockHttpServletRequest("GET", + "/test/path"); + final MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + willAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + response.setStatus(200); + response.setCommitted(true); + throw new IOException(); + } + }).given(chain).doFilter(request, response); + try { + filter.doFilter(request, response, chain); + fail(); + } + catch (IOException ex) { + // Continue + } + verify(context.getBean(CounterService.class)) + .increment(eq("status.200.test.path")); + context.close(); + } + @Configuration public static class Config {