3

I'm using the following code (from this answer) to configure headers to be logged on WebClient requests:

ExchangeStrategies exchangeStrategies = ExchangeStrategies.withDefaults();
exchangeStrategies
    .messageWriters().stream()
    .filter(LoggingCodecSupport.class::isInstance)
    .forEach(writer -> ((LoggingCodecSupport)writer).setEnableLoggingRequestDetails(true));

client = WebClient.builder()
    .exchangeStrategies(exchangeStrategies)

This works, but causes my Jackson configuration to be lost. In my application.properties I have:

spring.jackson.default-property-inclusion=non-null
spring.jackson.deserialization.accept-empty-string-as-null-object=true

which gets overwritten by the above code. Here is my workaround:

  @Autowired ObjectMapper objectMapper;

  @Bean
  WebClientCustomizer webClientCustomizer() {
    return (WebClient.Builder builder) -> {
      builder
          .exchangeStrategies(createExchangeStrategiesWhichLogHeaders())
    };
  }

  private ExchangeStrategies createExchangeStrategiesWhichLogHeaders() {
    ExchangeStrategies exchangeStrategies =
        ExchangeStrategies.builder()
            .codecs(
                clientDefaultCodecsConfigurer -> {
                  clientDefaultCodecsConfigurer
                      .defaultCodecs()
                      .jackson2JsonEncoder(
                          new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
                  clientDefaultCodecsConfigurer
                      .defaultCodecs()
                      .jackson2JsonDecoder(
                          new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
                })
            .build();

    exchangeStrategies
        .messageWriters()
        .stream()
        .filter(LoggingCodecSupport.class::isInstance)
        .forEach(writer -> ((LoggingCodecSupport) writer).setEnableLoggingRequestDetails(true));

    return exchangeStrategies;
  }

This works, but feels a bit strange. The question is: do I need to include the jackson/objectMapper configuration like this, or is there a simpler way to avoid the Spring objectMapper configuration being overwritten?

Fletch
  • 4,829
  • 2
  • 41
  • 55

1 Answers1

1

As of Spring Boot 2.1.0, you can achieve this by enabling the following property:

spring.http.log-request-details=true

If you're on a previous Spring Boot version, you should be able to customize this without overwriting or rebuilding the whole configuration, like this:

@Configuration
static class LoggingCodecConfig {

    @Bean
    @Order(0)
    public CodecCustomizer loggingCodecCustomizer() {
        return (configurer) -> configurer.defaultCodecs()
                .enableLoggingRequestDetails(true);
    }

}
Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • 1
    In Spring Boot 2.7.x, this property is deprecated in favour of `spring.codec.log-request-details`. But I do not recommend it, it does not log the request and response bodies, and the header values are logged as ``. – pyb Mar 16 '23 at 15:43