How to Log the REST Request and Response

This article discusses a simple strategy to debug the Request and Response from a Jakarta EE Rest Service using Filters and CDI annotations.

When building a RESTful web service, it’s important to have robust logging capabilities in place to help you troubleshoot issues, monitor performance, and gain insights into user behavior. One way to achieve this is by using the ContainerResponseFilter and ContainerRequestFilter interfaces, which provide a way to intercept and log incoming requests and outgoing responses.

If you are new to REST Services Filters and Interceptors you can check this article to learn more: Coding Filters and Interceptors for your RESTFul services

What are ContainerRequestFilter and ContainerResponseFilter?

ContainerRequestFilter and ContainerResponseFilter are interfaces available by the Jakarta API for RESTful Web Services specification that allow developers to add custom processing logic to the request and response processing pipeline.

  • ContainerRequestFilter allows to intercept incoming requests before they reach to the resource method. This allows you to perform pre-processing tasks such as authentication, validation, or data conversion. For example, you could use a ContainerRequestFilter to check the request headers or query parameters and reject any requests that don’t meet certain criteria.
  • ContainerResponseFilter, on the other hand, allows to intercept outgoing responses before they are reach to the client. This allows you to modify or add to the response headers, or to perform post-processing tasks such as logging, caching, or compression.

The following diagram depicts the sequence of an HTTP Request and the corresponding HTTP Response with the filters in place:

rest service debug request response

Creating a sample RESTFul application

As proof of concept, we will now create a sample Jakarta RESTful application which uses both filters to debug the Request and Response. Firstly, before defining the filters, we recommend to define a NameBinding annotation for it:

@NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface Log { }

This will make your application more modular so that you can apply Logging filters only on methods using the above annotation (@Log).

Logging REST Requests

To log incoming requests, you can use a ContainerRequestFilter to intercept the request and extract information such as the request method, URL, headers, and body. You can then log this information to a file, database, or other storage medium.

Here’s an example implementation of a ContainerRequestFilter that prints the Headers available in the Request:

@Provider
@Log
public class RequestLoggingFilter implements ContainerRequestFilter {
    private static final Logger logger = Logger.getLogger(RequestLoggingFilter.class.getName());


    @Override
    public void filter(ContainerRequestContext crc) {
        System.out.println(crc.getMethod() + " " + crc.getUriInfo().getAbsolutePath());
        for (String key : crc.getHeaders().keySet()) {
            logger.info("[REST Logging] " +key + ": " + crc.getHeaders().get(key));
        }
    }
}

Then, in order to allow the LoggingFilter in your REST Endpoint, simply add the @Log annotation on top of your Endpoint:

@GET
@Log
public Response hello() {
		return Response.ok("Example response")
		.build();
}

If you request the above Endpoint, you will see in the Server Console the list of Keys/Values available in the Request Headers:

[REST Logging] Accept: [text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8]
[REST Logging] Accept-Encoding: [gzip, deflate, br]
[REST Logging] Accept-Language: [en-US,en;q=0.5]
[REST Logging] Connection: [keep-alive]
[REST Logging] Cookie: [cookieName=cookieValue; _ga=GA1.1.639842581.1646586098; OAuth_Token_Request_State=347c7dda-97b7-44ee-9333-245e351535cb]
[REST Logging] Host: [localhost:8080]
[REST Logging] Sec-Fetch-Dest: [document]
[REST Logging] Sec-Fetch-Mode: [navigate]
[REST Logging] Sec-Fetch-Site: [none]
[REST Logging] Sec-Fetch-User: [?1]
[REST Logging] Upgrade-Insecure-Requests: [1]
[REST Logging] User-Agent: [Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0]

Logging REST Responses

To log outgoing responses, you can use a ContainerResponseFilter to intercept the response and extract information such as the response status, headers, and body. You can then log this information to a file, database, or other storage medium.

Here’s an example implementation of a ContainerResponseFilter that logs the Cookies that have been added in our REST Endpoint:

@Log
@Provider
public class ResponseLoggingFilter implements ContainerResponseFilter {
    private static final Logger logger = Logger.getLogger(ResponseLoggingFilter.class.getName());
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        Map<String, NewCookie> cookies = responseContext.getCookies();
        if (cookies != null && !cookies.isEmpty()) {
            logger.info("Response cookies:");
            for (Map.Entry<String, NewCookie> entry : cookies.entrySet()) {
                String name = entry.getKey();
                NewCookie cookie = entry.getValue();
                logger.info(name + "=" + cookie.getValue());
            }
        }
    }
}

Then, in order to add a new Cookie in the Response, we can modify the Endpoint as follows:

@GET
@Log
public Response hello() {
	NewCookie cookie = new NewCookie("cookieName", "cookieValue");
	return Response.ok("Example response")
			.cookie(cookie)
			.build();
}

Finally, deploy the application and check that the Console also includes the Response Filter information:

Response cookies:
cookieName=cookieValue

Conclusion

Logging is an essential part of any web service, and the ContainerRequestFilter and ContainerResponseFilter interfaces provided by JAX-RS are a great way to add logging capabilities to your RESTful web service. By implementing these filters, you can log incoming requests and outgoing responses, and gain valuable insights into your web service’s performance and usage.

Source code for this article: https://github.com/fmarchioni/mastertheboss/tree/master/jax-rs/logging