I have a RESTful API using JSON as request/reply format and I would like to log the payload sent by the client and the response sent by the API.
(Spring Boot version defined in my pom.xml is 2.2.1.RELEASE)
Spring provides a very conveniant Filter to do so :
@Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(10000);
filter.setIncludeHeaders(false);
return filter;
}
But it doesn't work : no payload is logged !
If I dig into the code the interesting part in the extended class AbstractRequestLoggingFilter.doFilterInternal
:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
[...]
if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
requestToUse = new ContentCachingRequestWrapper(request, getMaxPayloadLength());
}
[...]
}
It uses ContentCachingRequestWrapper
to workaround the fact the payload is a Stream and so can be consumed only once.
The construct inits a ByteArrayOutputStream to cache the payload:
public ContentCachingRequestWrapper(HttpServletRequest request, int contentCacheLimit) {
super(request);
this.cachedContent = new ByteArrayOutputStream(contentCacheLimit);
this.contentCacheLimit = contentCacheLimit;
}
But it doesn't copy the content of the stream into the var cachedContent
except if you call the method writeRequestParametersToCachedContent
(via getParameterValues
for example) which is never the case and so the stream remains to 0.
Questions:
Why the hell the stream isn't copied in the constructor ?
Is there a workaround to do not reimplement everything just because
ContentCachingRequestWrapper
is buggy ?
Thank you