The application should log the following information without impacting a client, asynchronously(in a separate thread).
- Request HTTP Method and URI
- Request Headers (Except the default)
- Client's IP Address
- Request Processing Time(In milliseconds)
- Request Body
- Response Body
If we consume inputstream
in the filter, then it cant be consumed again by spring for json to object mapping. Somewhere during the input stream to object mapping, can we plug our logger?
Update:
We can write over logging code in a MessageConverter, but it doesnt seems to be a good idea.
public class MyMappingJackson2MessageConverter extends AbstractHttpMessageConverter<Object> {
...
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
InputStream inputStream = inputMessage.getBody();
String requestBody = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
String method = request.getMethod();
String uri = request.getRequestURI();
LOGGER.debug("{} {}", method, uri);
LOGGER.debug("{}", requestBody);
return objectMapper.readValue(requestBody, clazz);
}
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
String responseBody = objectMapper.writeValueAsString(o);
LOGGER.debug("{}", responseBody);
outputMessage.getBody().write(responseBody.getBytes(StandardCharsets.UTF_8));
}
}
You can achieve this using spring aspect. It provides you some annotations like:
@Before , @AfterReturning, @AfterThrowing
etc. You may not don't need all endpoints log, so here have some filters based on package. Here are some examples:For Request:
For Response:
For Exception:
Here is the full code:
More info about AOP visit here:
Spring docks about AOP
Sample article about AOP
I would use 2 elements: A LoggingFilter and the Async support from Spring. For the first one, I would use a CommonsRequestLoggingFilter that already knows how to intercept the HTTP requests, create the configuration for that and the Async. You can do something like:
First Enable Async Support
Then Create the loggingFilter:
Then create a custom logging configuration for the filter that you created:
To extract the data from the request you can use the
message
parameter or process theHttpServletRequest
. Take as an example:An answer from baeldung.com :
To make the logging asynchronous, we may use asynchronous appenders. Unfortunately it does not support logging response payloads. :(
I guess your best option is to do the logging in an Async Method.
Please refer to:
Async
How to Async