spring-bootspring-webfluxmicrometerobservability

Spring boot 3.4+ webclient reactive depracated metrics filter alternative


I have spring boot 3.4+ reactive webflux app

we have been using below config to get prometheus metrics (Spring Boot 2.x)

    private ExchangeFilterFunction metricsWebClientFilterFunction(String name) {
        log.info("Register filter function with name: {}", name);
        return new MetricsWebClientFilterFunction(meterRegistry, new DefaultWebClientExchangeTagsProvider(), name, AutoTimer.ENABLED);
    }

But due to new spring boot version with observability API this is not working anymore,

We have tried using below config

WebClient.builder()
                .observationRegistry(registry)
    

Also tried various NamingConventionConfig classes, @Observable but it doesn't help.

We need metrics populated like below

Correct

http_client_requests_seconds{error="none",status="200",uri="/endpoint/",quantile="0.9"} 0.0

We're getting unknown uri metrics like below

http_server_requests_active_seconds_bucket{exception="none",method="GET",outcome="SUCCESS",status="200",uri="UNKNOWN",le="274.877906944"} 1

Solution

  • Figured out a way to achieve similar metrics with spring boot 3.4+ with below configs

    private final ObservationRegistry registry;
    public WebClientConfig(ObservationRegistry registry) {
        this.registry = registry;
    }
    
    public WebClient webClient(String webClientName, String host) {
        HttpClient httpClient = configureHttpClient();
        return WebClient.builder()
                .baseUrl(host)
                .observationRegistry(registry)
                .observationConvention(new DefaultClientRequestObservationConvention(webClientName))
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }
    

    And then in the connector class using below code to call external service where

    @Autowired
    @Qualifier("{qualifierName}")
    private WebClient webClient;
    
    @Value("${endpoint from yaml}")
    private String endpoint;
    
    public Mono<TargetType> getReq(Integer reqNumber) {
        return webClient.get()
                .uri(endpoint, reqNumber)
                .retrieve()
                .bodyToFlux(TargetType.class)
                .next()
    }
    

    This produces correct metrics with right URI including {reqNumber}, status, method