How to trace HTTP Requests in Spring Boot using a Filter

This tutorial shows how to trace HTTP requests using different options such as the CommonsRequestLoggingFilter . We will also show how to dump HTTP request for reactive applications using Spring Boot’s WebClient.

There are several options to trace the incoming HTTP Requests of a Spring Boot application. You can also opt for a zero-code solution by using Spring Boot Actuator. This tutorial discusses it in detail: How to trace HTTP Requests with Spring Boot Actuator

Using CommonsRequestLoggingFilter

One of the simplest option is to use the CommonsRequestLoggingFilter which you can add a Bean in your configuration. See the following example:

package com.example.testrest;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CommonsRequestLoggingFilter;

@Configuration
public class RequestLoggerFilter {
  @Bean
  public CommonsRequestLoggingFilter logFilter() {
    CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
    filter.setIncludeQueryString(true);
    filter.setIncludePayload(true);
    filter.setMaxPayloadLength(10000);
    filter.setIncludeHeaders(false);
    filter.setAfterMessagePrefix("REQUEST DATA : ");
    return filter;
  }
}

You also need to set the logging level for CommonsRequestLoggingFilter in the application.properties file:

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG 

Or as an alternative, in logback.xml:

<?xml version="1.0" encoding="UTF-8"?><logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
        
   <level value="DEBUG"/>
    
</logger>

When you run the application, you should be able to see the incoming request in your Spring Boot Console:

2020-04-09 15:53:06.554 DEBUG 13536 --- [nio-8080-exec-1] o.s.w.f.CommonsRequestLoggingFilter      : Before request [uri=/list] 2020-04-09 15:53:06.630 DEBUG 13536 --- [nio-8080-exec-1] o.s.w.f.CommonsRequestLoggingFilter      : REQUEST DATA : uri=/list] 

On the other hand, if you want to receive the HTTP Request as a Stream, you can do that by extending the HandlerInterceptorAdapter class:

@Component public class CustomHandlerInterceptorAdapter extends HandlerInterceptorAdapter {
  @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    ServletRequest servletRequest = new ContentCachingRequestWrapper(request);
    servletRequest.getParameterMap();
    // Read inputStream and log it
    return true;
  }
}

Capturing WebClient Requests

WebClient is part of the Spring WebFlux framework, which operates on the Reactive Stack. It provides a functional, fluent API based on Reactor, allowing declarative composition of asynchronous logic without dealing with threads or concurrency.

The following WebClientLoggingFilter class allows to log the details of HTTP requests and responses made using Spring’s WebClient. This can be particularly useful for debugging, monitoring, and tracing the interactions between your application and external services.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import reactor.core.publisher.Mono;

public class WebClientLoggingFilter {

    private static final Logger logger = LoggerFactory.getLogger(WebClientLoggingFilter.class);

    public static ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            logger.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value)));
            return Mono.just(clientRequest);
        });
    }

    public static ExchangeFilterFunction logResponse() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            logger.info("Response Status: {}", clientResponse.statusCode());
            clientResponse.headers().asHttpHeaders().forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value)));
            return Mono.just(clientResponse);
        });
    }
}

In order to enable WebClient in your application, you need to include the following configuration in your project:

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

By using these logging filters, you can gain insights into the HTTP interactions of your application, making it easier to debug issues and monitor the application’s behavior

Found the article helpful? if so please follow us on Socials
Twitter Icon       Facebook Icon       LinkedIn Icon       Mastodon Icon