eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – Diagrid – NPI EA (cat= Testing)
announcement - icon

In distributed systems, managing multi-step processes (e.g., validating a driver, calculating fares, notifying users) can be difficult. We need to manage state, scattered retry logic, and maintain context when services fail.

Dapr Workflows solves this via Durable Execution which includes automatic state persistence, replaying workflows after failures and built-in resilience through retries, timeouts and error handling.

In this tutorial, we'll see how to orchestrate a multi-step flow for a ride-hailing application by integrating Dapr Workflows and Spring Boot:

>> Dapr Workflows With PubSub

1. Introduction

Sometimes we might have to do some additional processing, such as logging, on the HTTP request payload. Logging the incoming HTTP request is very helpful in debugging applications.

In this quick tutorial, we’ll learn the basics of logging incoming requests using Spring Boot’s logging filter.

2. Maven Dependency

Let’s start by adding the spring-boot-starter-web dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.2.2</version>
</dependency>

This dependency provides all the core requirements to log the incoming requests in a Spring Boot application.

3. Basic Web Controller

First, we’ll define a controller to use in our example:

@RestController
public class TaxiFareController {

    @GetMapping("/taxifare/get/")
    public RateCard getTaxiFare() {
        return new RateCard();
    }
    
    @PostMapping("/taxifare/calculate/")
    public String calculateTaxiFare(
      @RequestBody @Valid TaxiRide taxiRide) {
 
        // return the calculated fare
    }
}

In the next sections, we’ll see how to log incoming requests to the Spring Boot application.

4. Using Custom Request Logging

We want to use a custom Filter to capture the request payload before a controller receives the request.

4.1. Wrapping HTTP Request

We need to wrap the HTTP request and log its payload. The HttpServletRequestWrapper class provides the ability to wrap and modify incoming HttpServletRequest objects.

Firstly, let’s create the CachedHttpServletRequest class that extends HttpServletRequestWrapper class:

public class CachedHttpServletRequest extends HttpServletRequestWrapper {

    private byte[] cachedPayload;

    public CachedHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        InputStream requestInputStream = request.getInputStream();
        this.cachedPayload = StreamUtils.copyToByteArray(requestInputStream);
    }
}

In the above code, first, we read the actual request body inside the wrapper constructor and store it in the cachedPayload byte array.

Then, we override getInputStream() and getReader() methods:

@Override
public ServletInputStream getInputStream() {
    return new CachedServletInputStream(this.cachedPayload);
}

@Override
public BufferedReader getReader() {
    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedPayload);
    return new BufferedReader(new InputStreamReader(byteArrayInputStream));
}

In the getInputStream() method, we return the new extended ServletInputStream object with the cachedPayload. Also, we override the getReader() method. This method returns a BufferedReader object that can be used to read the body of the request as character data.

4.2. Extending ServletInputStream

As we mentioned, we need to extend ServletInputStream class to create our wrapper. Let’s create the CachedServletInputStream class:

public class CachedServletInputStream extends ServletInputStream {

    private final static Logger LOGGER = LoggerFactory.getLogger(CachedServletInputStream.class);
    private InputStream cachedInputStream;

    public CachedServletInputStream(byte[] cachedBody) {
        this.cachedInputStream = new ByteArrayInputStream(cachedBody);
    }
}

In this class, first, we create a new constructor with cachedBody and return a new ByteArrayInputStream object from it. We use this InputStream object in other overridden methods.

Then, we override the isFinished(), isReady(), setReadListener(), and read() methods:

@Override
public boolean isFinished() {
    try {
        return cachedInputStream.available() == 0;
    } catch (IOException exp) {
        LOGGER.error(exp.getMessage());
    }
    return false;
}

@Override
public boolean isReady() {
    return true;
}

@Override
public void setReadListener(ReadListener readListener) {
    throw new UnsupportedOperationException();
}

@Override
public int read() throws IOException {
    return cachedInputStream.read();
}

The isReady() method is used to check if data can be read without blocking and then the data is read. The read() method reads from the cachedInputStream object. The isFinished() method returns true when all the data from the stream has been read, else it returns false.

4.3. Custom Filter

After that, we’ll create a filter class that extends OncePerRequestFilter class. Then, we’ll override the doFilterInternal() method. In doFilterInternal() method, we use our custom request wrapper to get the request payload and log it.

Let’s create a RequestCachingFilter class:

@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Component
@WebFilter(filterName = "RequestCachingFilter", urlPatterns = "/*")
public class RequestCachingFilter extends OncePerRequestFilter {

    private final static Logger LOGGER = LoggerFactory.getLogger(RequestCachingFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {
        CachedHttpServletRequest cachedHttpServletRequest = new CachedHttpServletRequest(request);
        LOGGER.info("REQUEST DATA: " + IOUtils.toString(cachedHttpServletRequest.getInputStream(), StandardCharsets.UTF_8));
        filterChain.doFilter(cachedHttpServletRequest, response);
    }
}

Additionally, the filter is mapped to all of the requests in the application with the URL mapping /*.

In the next section, we’ll use Spring Boot’s built-in request logging solution.

5. Using Spring Boot Built-In Request Logging

Spring Boot provides a built-in solution to log payloads. We can use the ready-made filters by plugging into the Spring Boot application using configuration.

AbstractRequestLoggingFilter is a filter that provides the basic functions of logging. Subclasses should override the beforeRequest() and afterRequest() methods to perform the actual logging around the request.

The Spring Boot framework provides three concrete implementation classes that we can use to log incoming requests:

  • CommonsRequestLoggingFilter
  • Log4jNestedDiagnosticContextFilter (deprecated)
  • ServletContextRequestLoggingFilter

Now, let’s move on to the CommonsRequestLoggingFilter, and configure it to capture incoming requests for logging.

5.1. Configure Spring Boot Application

We can configure the Spring Boot application by adding a bean definition to enable request logging:

@Configuration
public class RequestLoggingFilterConfig {

    @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;
    }
}

5.2. Configure Logging Level

This logging filter also requires us to set the log level to DEBUG. We can enable the DEBUG mode by adding the below element in logback.xml:

<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter">
    <level value="DEBUG" />
</logger>

Another way of enabling the DEBUG level log is to add the following in application.properties:

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

Now, the application is ready to test.

6. Example in Action

Finally, let’s write a test to see how to log the incoming request:

@Test
public void givenRequest_whenFetchTaxiFareRateCard_thanOK() {
    TestRestTemplate testRestTemplate = new TestRestTemplate();
    TaxiRide taxiRide = new TaxiRide(true, 10l);
    String fare = testRestTemplate.postForObject(
      URL + "calculate/", 
      taxiRide, String.class);
 
    assertThat(fare, equalTo("200"));
}

When we execute our test case, we’ll see the following output in the console:

18:24:04.318 [] INFO  c.b.web.log.app.RequestCachingFilter - REQUEST DATA: {"isNightSurcharge":true,"distanceInMile":10}
18:24:04.321 [] DEBUG o.s.w.f.CommonsRequestLoggingFilter - Before request [POST /spring-rest/taxifare/calculate/]
18:24:04.429 [] DEBUG o.s.w.f.CommonsRequestLoggingFilter - REQUEST DATA: POST /spring-rest/taxifare/calculate/, payload={"isNightSurcharge":true,"distanceInMile":10}]

We can see that the request payload is printed to the console due to the invocation of the RequestCachingFilter and CommonsRequestLoggingFilter classes.

7. Conclusion

In this article, we learned how to implement basic web request logging using a custom filter in the Spring Boot application. Then we discussed the Spring Boot built-in filter class, which provides ready-to-use and simple logging mechanisms.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)