Skip to content

Current Observation.Context missing from WebClient request #31609

Closed
@amrynsky

Description

@amrynsky

Spring Boot: 3.1.5
Spring Framework: 6.0.13

In Spring 3 micrometer integration has been reworked to use Micrometer 1.10 Observation. It works in the default setup but in case there is a filter (ExchangeFilterFunction) that changes the underlining request, metric is reported with incorrect tags.

It happens because current implementation is initializing ClientRequestObservationContext using the original ClientRequest

and any changes to the request after this point are not visible to the observation context

Similar scenario was supported in the previous version by adding custom filters before MetricsWebClientFilterFunction that reported the same metric before.

Here is a test to reproduce the above issue. In this test original request uses POST http method but filter is changing is to GET. The metric is still reported with the original POST method.

iterable contents differ at index [3], expected: <tag(method=GET)> but was: <tag(method=POST)>
Expected :tag(method=GET)
Actual   :tag(method=POST)
@SpringBootTest(
        properties = {"management.metrics.tags.service-name=test"}
)
class WebClientObservationTest {
    @Autowired
    private WebClient.Builder webClientBuilder;

    @Autowired
    private MeterRegistry meterRegistry;

    @Test
    void httpClientRequestsMetrics() {
        var webClient = webClientBuilder
                .filter(new ClientRequestExchangeFilter())
                .build();

        var req = webClient.post()
                .uri("http://api.zippopotam.us/us/{zip}", 98121)
                .retrieve()
                .bodyToMono(String.class);

        StepVerifier.create(req)
                .assertNext(res -> {
                    assertNotNull(res);
                })
                .verifyComplete();

        Meter meter = meterRegistry.find("http.client.requests")
                .meter();
        assertNotNull(meter);

        List<Tag> expectedTags = Arrays.asList(
                Tag.of("client.name", "api.zippopotam.us"),
                Tag.of("error", "none"),
                Tag.of("exception", "none"),
                Tag.of("method", "GET"),
                Tag.of("outcome", "SUCCESS"),
                Tag.of("service-name", "test"),
                Tag.of("status", "200"),
                Tag.of("uri", "/us/{zip}")
        );
        assertIterableEquals(expectedTags, meter.getId().getTags());
    }

    static class ClientRequestExchangeFilter implements ExchangeFilterFunction {
        @Override
        public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
            ClientRequest newRequest = ClientRequest.from(request)
                    .method(HttpMethod.GET)
                    .build();
            return next.exchange(newRequest);
        }
    }

    @TestConfiguration
    public static class MockConfiguration {
        @Bean
        public MeterRegistry simpleMeterRegistry() {
            return new SimpleMeterRegistry();
        }
    }
}

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: backportedAn issue that has been backported to maintenance branchestheme: observabilityAn issue related to observability and tracingtype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions