For Spring Boot Webclient, what is the preferred mechanism to log non-parseable responses?

16 Views Asked by At

Here is my setup. I have most code using .bodyToMono via webflux. However, in the event of a parse error, Webclient has no good way to get the original body that caused the issue. In this example, assume 2xx response, however instead of returning properly formatted json, something else came, maybe a html or plain text etc. I would like to log the value of this malformed response and then return it in some way to a calling client. The only path I can see within Webflux to do this would be to always convert the body to a string near the top of the chain and attempt to manually deserialize via object mapper. In my non-parseable scenario, relying on the webflux apis only show me the tokens the parsing failed on, not the entire response. For observability, traceability etc this seems like kind of a fatal flaw. Is there another path to this goal I'm missing?

1

There are 1 best solutions below

0
stelios.anastasakis On

You should add some code snippet and throwable to see what exactly is going on.

In general, the way I handle it is as you mentioned: first .bodyToMono(String.class) and then create the JSON object. If exception is thrown you can immediately log the whole string body like this:

    private Mono<String> handleClientResponse(ClientResponse clientResponse) {
        Mono<String> responseBodyMono = clientResponse.bodyToMono(String.class);
        HttpStatusCode responseStatus = clientResponse.statusCode();
        if (responseStatus.isError()) {
            return responseBodyMono.flatMap(errorBody ->
                    Mono.error(...)
            );
        } else {
            return responseBodyMono
                    .flatMap(responseBody -> {
                        try {
                            JSONObject jsonObject = new JSONObject(responseBody);
                            return Mono.just(jsonObject.getString(JSON_ATTRIBUTE_KEY));
                        } catch (Exception ex) {
                            log.error("Invalid response body with message: [{}]", ex.getMessage(), ex);
                            log.error("Response body was: [{}]", responseBody);
                            return Mono.error(...);
                        }
                    });
        }
    }

Have you tried something like this?

Note: for observability/traceability you can always use other patterns, like metrics, trace-request-ids etc. Just logging is not enough for real time services