Request/Response logging in Spring Boot Application

Introduction

There are scenarios where you would want to log full request/response payloads in a Spring Boot application. This recipe shows you how to utilize logback to achieve the desired results.

Required Configuration

Below is a sample POM with required dependencies.

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <logback.version>1.2.3</logback.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>net.rakugakibox.spring.boot</groupId>
            <artifactId>logback-access-spring-boot-starter</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
            <version>${logback.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
    </dependencies>        

Create a logback-access.xml under src/main/resources with the following configuration: You can change what all fields are displayed in access log. For a full list of available fields, please refer to logback documentation.

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>logging uri: %requestURL | status code: %statusCode | bytes: %bytesSent | elapsed time: %elapsedTime | request-log: %magenta(%requestContent) | response-log: %cyan(%responseContent)</pattern>
        </encoder>
    </appender>
    <appender-ref ref="STDOUT"/>
</configuration>

Create a Servlet Filter that intercepts the requests:

import ch.qos.logback.access.servlet.TeeFilter;

@Configuration
public class FilterConfiguration {

    @Autowired
    @Bean
    public FilterRegistrationBean requestResponseFilter() {

        final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
        TeeFilter filter = new TeeFilter();
        filterRegBean.setFilter(filter);
        filterRegBean.setUrlPatterns("/rest/path");
        filterRegBean.setName("Request Response Filter");
        filterRegBean.setAsyncSupported(Boolean.TRUE);
        return filterRegBean;
    }
}

Once this is configured, every request/response payloads (not form POST) will be logged to your default appender.

Enabling/Disabling Logging

There are potential impacts to application performance once this filter is activated since every request/response payload is copied to an in memory buffer and hence additional overheads to garbage collection and CPU. Also, you have to be careful about not logging sensitive data. So, there are configurations available to disable this filter by default.

Add this to your application.properties to disable access logging by default:

logback.access.enabled=false

Improvements

It would be nice to have the filter skip/obfuscate contents of the request/response based on a pattern. The default TeeFilter can be extended to achieve this result.

Kontakt