You can create your own wrapper/proxy class around the JSON encoder and intercept the serialized body before it is sent into the intertubes.
This blog post shows how to log the JSON payloads of WebClient requests and responses
Specifically, you would extend the encodeValue method (or encodeValues in case of streaming data) of Jackson2JsonEncoder. Then you can do with that data what you wish, such as logging etc. And you could even do this conditionally based on environment/profile
This custom logging-encoder can be specified when creating the WebClient, by codecs:
CustomBodyLoggingEncoder bodyLoggingEncoder = new CustomBodyLoggingEncoder();
WebClient.builder()
.codecs(clientDefaultCodecsConfigurer -> {
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(bodyLoggingEncoder);
clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
})
...
Update 2020/7/3:
Here is a rushed example applying the same principle but for a decoder:
public class LoggingJsonDecoder extends Jackson2JsonDecoder {
private final Consumer<byte[]> payloadConsumer;
public LoggingJsonEncoder(final Consumer<byte[]> payloadConsumer) {
this.payloadConsumer = payloadConsumer;
}
@Override
public Mono<Object> decodeToMono(final Publisher<DataBuffer> input, final ResolvableType elementType, final MimeType mimeType, final Map<String, Object> hints) {
// Buffer for bytes from each published DataBuffer
final ByteArrayOutputStream payload = new ByteArrayOutputStream();
// Augment the Flux, and intercept each group of bytes buffered
final Flux<DataBuffer> interceptor = Flux.from(input)
.doOnNext(buffer -> bufferBytes(payload, buffer))
.doOnComplete(() -> payloadConsumer.accept(payload.toByteArray()));
// Return the original method, giving our augmented Publisher
return super.decodeToMono(interceptor, elementType, mimeType, hints);
}
private void bufferBytes(final ByteArrayOutputStream bao, final DataBuffer buffer) {
try {
bao.write(ByteUtils.extractBytesAndReset(buffer));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
You would configure that along with the encoder using the codecs builder method on WebClient.
Of course this above only works assuming your data is being deserialized to a Mono. But override other methods if you need it. Also I'm just stdout'ing the resulting JSON there, but you could pass in a Consumer<String> or something for the decoder to send the string to for example, or just log from there ; up to you.
A word of warning that in it's current form this is going to be doubling your memory usage, as it's buffering the entire response. If you can send that byte data off to another process/thread to write to log file or some output stream (or Flux even) immediately, you could avoid buffering the whole payload in memory.