Commit a3c6e72e authored by Phillip Webb's avatar Phillip Webb

Merge pull request #11348 from GreyTeardrop

* pr/11348:
  Polish MetricsFilter registration async support
  Fix MetricsFilter registration to support async
parents 25815ca7 0b689a5b
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.metrics.web.servlet; package org.springframework.boot.actuate.autoconfigure.metrics.web.servlet;
import javax.servlet.DispatcherType;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
...@@ -27,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; ...@@ -27,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
...@@ -51,13 +54,17 @@ public class WebMvcMetricsConfiguration { ...@@ -51,13 +54,17 @@ public class WebMvcMetricsConfiguration {
} }
@Bean @Bean
public WebMvcMetricsFilter webMetricsFilter(MeterRegistry registry, public FilterRegistrationBean<WebMvcMetricsFilter> webMetricsFilter(
MetricsProperties properties, WebMvcTagsProvider tagsProvider, MeterRegistry registry, MetricsProperties properties,
WebApplicationContext context) { WebMvcTagsProvider tagsProvider, WebApplicationContext context) {
Server serverProperties = properties.getWeb().getServer(); Server serverProperties = properties.getWeb().getServer();
return new WebMvcMetricsFilter(context, registry, tagsProvider, WebMvcMetricsFilter filter = new WebMvcMetricsFilter(context, registry,
serverProperties.getRequestsMetricName(), tagsProvider, serverProperties.getRequestsMetricName(),
serverProperties.isAutoTimeRequests()); serverProperties.isAutoTimeRequests());
FilterRegistrationBean<WebMvcMetricsFilter> registration = new FilterRegistrationBean<>(
filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);
return registration;
} }
} }
...@@ -19,6 +19,10 @@ package org.springframework.boot.actuate.autoconfigure.metrics; ...@@ -19,6 +19,10 @@ package org.springframework.boot.actuate.autoconfigure.metrics;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.MockClock; import io.micrometer.core.instrument.MockClock;
...@@ -83,6 +87,9 @@ public class MetricsAutoConfigurationIntegrationTests { ...@@ -83,6 +87,9 @@ public class MetricsAutoConfigurationIntegrationTests {
@Autowired @Autowired
private MeterRegistry registry; private MeterRegistry registry;
@Autowired
private CyclicBarrier cyclicBarrier;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
public void restTemplateIsInstrumented() { public void restTemplateIsInstrumented() {
...@@ -111,6 +118,21 @@ public class MetricsAutoConfigurationIntegrationTests { ...@@ -111,6 +118,21 @@ public class MetricsAutoConfigurationIntegrationTests {
.hasAtLeastOneElementOfType(JvmMemoryMetrics.class); .hasAtLeastOneElementOfType(JvmMemoryMetrics.class);
} }
@Test
public void asyncRequestMappingIsInstrumented()
throws InterruptedException, BrokenBarrierException {
Thread backgroundRequest = new Thread(
() -> this.loopback.getForObject("/api/async", String.class));
backgroundRequest.start();
this.cyclicBarrier.await();
MockClock.clock(this.registry).addSeconds(2);
this.cyclicBarrier.await();
backgroundRequest.join();
assertThat(this.registry.find("http.server.requests").tags("uri", "/api/async")
.timer()).matches(t -> t.count() == 1)
.matches(t -> t.totalTime(TimeUnit.SECONDS) == 2);
}
@Configuration @Configuration
@ImportAutoConfiguration({ MetricsAutoConfiguration.class, @ImportAutoConfiguration({ MetricsAutoConfiguration.class,
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
...@@ -130,16 +152,44 @@ public class MetricsAutoConfigurationIntegrationTests { ...@@ -130,16 +152,44 @@ public class MetricsAutoConfigurationIntegrationTests {
return restTemplateBuilder.build(); return restTemplateBuilder.build();
} }
@Bean
public CyclicBarrier cyclicBarrier() {
return new CyclicBarrier(2);
}
} }
@RestController @RestController
static class PersonController { static class PersonController {
private final CyclicBarrier cyclicBarrier;
PersonController(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@GetMapping("/api/people") @GetMapping("/api/people")
Set<String> personName() { Set<String> personName() {
return Collections.singleton("Jon"); return Collections.singleton("Jon");
} }
@GetMapping("/api/async")
CompletableFuture<String> asyncHello()
throws BrokenBarrierException, InterruptedException {
this.cyclicBarrier.await();
return CompletableFuture.supplyAsync(this::awaitAndHello);
}
private String awaitAndHello() {
try {
this.cyclicBarrier.await();
return "async-hello";
}
catch (InterruptedException | BrokenBarrierException ex) {
throw new RuntimeException(ex);
}
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment