Spring

Spring Http Request Logging

Introduction:

Logging the Http requests in a web application is a very common requirement. In this tutorial, we’ll learn to log all our incoming Http requests in Spring framework.

To follow along with the tutorial, we assume that the reader has an understanding of spring-core and Logback.

Using CommonsRequestLoggingFilter:

A pretty simple way to log all our incoming requests in Spring Boot application involves configuring CommonsRequestLoggingFilter bean. We’ll have to define this bean in our Configuration class:

@Configuration
public class AppConfig {

....

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

...
}

In addition to that, we have to set the log level to DEBUG for CommonsRequestLoggingFilter. So, let’s add:

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

in our logback.xml file.

With having the above configurations in place, we’ll be able to see the incoming requests being logged on our console.

Writing a Custom Filter:

What if, based on the business requirements we need to log our incoming requests in a specific format? One way to be able to achieve it would be to extend CommonsRequestLoggingFilter. The other approach we can take involves writing our own implementation audit filter.

An audit filter in our filter chain will be responsible for logging all incoming requests, the way we want it to. One important point to remember is that if we directly read the InputStream of our incoming request for the sake of logging, the entire request object will be consumed and can never be read again.

To prevent consuming the actual request, we need to cache our request. For that, we would make use of ContentCachingRequestWrapper class available in Spring framework.

Let’s get started by defining our audit filter:

public class HttpRequestAuditFilter implements Filter {

    private static final Logger LOG = LoggerFactory.
      getLogger(HttpRequestAuditFilter.class);
    private static int final MAX_PAYLAOD_LENGTH = 10000;
    ...

    public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {
        if((request instanceof HttpServletRequest) 
          && !(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        try {
            chain.doFilter(request, response);
        } finally {
            if(request instanceof HttpServletRequest) {
                performRequestAudit((HttpServletRequest)request);
            }
        }
    }

    public void performRequestAudit(HttpServletRequest httpRequest) {
        ContentCachingRequestWrapper wrapper =
          WebUtils.getNativeRequest(httpRequest, ContentCachingRequestWrapper.class);
        String payload = "";
        if (wrapper != null) {
            byte[] requestBuffer = wrapper.getContentAsByteArray();
            if (requestBuffer.length > 0) {
                int length = Math.min(requestBuffer.length, MAX_PAYLOAD_LENGTH);
                try {
                    payload = new String(requestBuffer,
                      0, length, wrapper.getCharacterEncoding());
                }
                catch (UnsupportedEncodingException unex) {
                    payload = "[Unsupported-Encoding]";
                }
            }
        }
	String headers = new ServletServerHttpRequest(request).getHeaders();
        LOG.trace("{}|{}", payload, headers);
    }

}
Steps Followed:
  1. Before the request is passed along the filter chain, we cached the request object
  2. We retrieve the request object from our wrapper in our finally block
  3. We further read the cached request payload along with the request headers
  4. Finally, we use our configured logger to log request header and payload

The above implementation only logs the request payload and the header. We can choose to extend it to log the query string, remote address, and other such request parameters.

 

Conclusion:

In this tutorial, we looked at two ways in which we can log our incoming Http request in a Spring or Spring Boot framework. We can further refine our strategies based on our requirements. Hope it helps!

 

Be the First to comment.

Leave a Comment

Your email address will not be published. Required fields are marked *