Issue
I am trying to log (just to console write now for simplicity sake) the final rendered HTML that will be returned by the HttpServletResponse. (i.e. the body) To this end, I am using the HandlerInterceptorAdapter from Spring MVC like so:
public class VxmlResponseInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(response.toString());
}
}
This works as expected and I see the HTTP response headers in the console. My question is if there is a relatively simple way to log the entire response body (i.e. final rendered HTML) to the console without having to resort to doing jumping jacks with PrintWriters, OutputStream's and the like.
Thanks in advance.
Solution
This would be better done using a Servlet Filter
rather than a Spring HandlerInterceptor
, for the reason that a Filter
is allowed to substitute the request and/or response objects, and you could use this mechanism to substitute the response with a wrapper which logs the response output.
This would involve writing a subclass of HttpServletResponseWrapper
, overriding getOutputStream
(and possibly also getWriter()
). These methods would return OutputStream
/PrintWriter
implementations that siphon off the response stream into a log, in addition to sending to its original destination. An easy way to do this is using TeeOutputStream
from Apache Commons IO, but it's not hard to implement yourself.
Here's an example of the sort of thing you could do, making use of Spring's GenericFilterBean
and DelegatingServletResponseStream
, as well as TeeOutputStream
, to make things easier:
public class ResponseLoggingFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse responseWrapper = loggingResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(request, responseWrapper);
}
private HttpServletResponse loggingResponseWrapper(HttpServletResponse response) {
return new HttpServletResponseWrapper(response) {
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new DelegatingServletOutputStream(
new TeeOutputStream(super.getOutputStream(), loggingOutputStream())
);
}
};
}
private OutputStream loggingOutputStream() {
return System.out;
}
}
This logs everything to STDOUT. If you want to log to a file, it'll get a big more complex, what with making sure the streams get closed and so on, but the principle remains the same.
Answered By - skaffman