How to configure my own AutoTimer in Spring 6

154 views Asked by At

I am working on the migration of the metrics of our app from the old APIs relying on WebMvcMetricsFilter to the new one, based on Micrometer 1.11, because we are migrating from Spring Boot 2.7.14 to 3.1.4.

Our previous metrics setup was as follows:

Before we were using a filter implementing WebMvcMetricsFilter:

public class AppWebMvcTimersFilter extends WebMvcMetricsFilter {

private final Predicate<String> predicate;


public AppWebMvcTimersFilter(
  final MeterRegistry registry,
  final WebMvcTagsProvider tagsProvider,
  final String metricName,
  final AutoTimer autoTimer,
  final Predicate<String> predicate) {
  super(registry, tagsProvider, metricName, autoTimer);
  this.predicate = predicate;
}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
  return predicate.test(request.getRequestURI());
 }
}

Then we had our implementation of AutoTimerdefining our own buckets, like so:

public class AppMetricAutoTimer implements AutoTimer {
  @Override
  public void apply(Timer.Builder builder) {
    builder
     .minimumExpectedValue(Duration.ofMillis(BUCKET_0))
     .maximumExpectedValue(Duration.ofMillis(BUCKET_10))
     .sla(
        Duration.ofMillis(BUCKET_0),
        Duration.ofMillis(BUCKET_1),
        Duration.ofMillis(BUCKET_2),
        Duration.ofMillis(BUCKET_3),
        Duration.ofMillis(BUCKET_4),
        Duration.ofMillis(BUCKET_5),
        Duration.ofMillis(BUCKET_6),
        Duration.ofMillis(BUCKET_7),
        Duration.ofMillis(BUCKET_8),
        Duration.ofMillis(BUCKET_9),
        Duration.ofMillis(BUCKET_10));
  }
}

And the two things bond in a Metrics configuration class to declare the beans:

  @Configuration
  public class AppMetricsConfiguration {

    @Bean
    MeterRegistry appSimpleMeterRegistry() {
      return new AppSimpleMeterRegistry(aggregatedTotalLatenciesLoader());
    }

    @Bean
    AutoTimer appMetricAutoTimer() {
      return new AppMetricAutoTimer();
    }

    @Bean
      WebMvcTagsProvider appWebMvcTagsProvider() {
        return new AppWebMvcTagsProvider();
    }
    
    @Bean
    WebMvcMetricsFilter appWebMvcTimerFilter(
      final MeterRegistry registry,
      final WebMvcTagsProvider metricWebMvcTagsProvider,
      final AutoTimer appAutoTimer) {
      return new AppWebMvcTimersFilter(
        registry,
        metricWebMvcTagsProvider,
        METRIC_FULL_NAME,
        appAutoTimer,
        uri -> !uri.startsWith(URI_API_PREFIX));
      }
    }

With the change of Observation APIS in Spring 6:

Now I've got rid of the WebMvcMetricsFilter. As before, we are configuring an interceptor to use a MeterRegistry to handle the different counters. But due to the removal of our implementation of WebMvcMetricsFilter, all of our tests verifying the latencies are now failing.

I haven't found in the documentation any way to provide a bean of AutoTimer to have the latencies sorted as per our configured buckets.

The question is: how is it supposed now to provide an AutoTimer in a similar way it was done before in the implementations of WebMvcMetricsFilter?

1

There are 1 answers

3
Jonatan Ivanov On

AutoTimer is not used anymore, if you want to modify your meters, you can either:

  1. Set things from properties, e.g.:
management.metrics.distribution.slo.http.server.requests=...
management.metrics.distribution.minimum-expected-value.http.server.requests=...
management.metrics.distribution.maximum-expected-value.http.server.requests=...

Please check the docs.

  1. You can create a MeterFilter and do the same from code:
@Bean
MeterFilter sloMeterFilter() {
    ...
}

Please check the boot and the micrometer docs.