How to use a filter to measure performance?

I am wondering if I can use a filter (in my case CorsFilter) to measure the time AND to put the time on the message itself. I know that the following works in order:

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { long startTime = System.nanoTime(); chain.doFilter(request, response); long endTime = System.nanoTime(); System.out.println("Time: " + (endTime - startTime) ); } 

Which, of course, displays the total time in seconds. I wanted to put time in the header of the returned response so that the recipient could look at the header and see how much time the processing took. The following code does not work:

 public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { long startTime = System.nanoTime(); if(response instanceof HttpServletResponse) { HttpServletResponse httpResp = (HttpServletResponse)response; httpResp.addHeader("Start-time", Long.toString(startTime)); } chain.doFilter(request, response); long endTime = System.nanoTime(); if(response instanceof HttpServletResponse) { HttpServletResponse httpResp = (HttpServletResponse)response; httpResp.addHeader("End-time", Long.toString(endTime)); } } 

The header includes only Start-time, not End-time. I assume this is because the message has already been sent, so changing the object will not have any effect.

Does anyone have an elegant / smart solution for setting timings in a header using a filter?

Thanks Phil

Update

I learned how to use HttpServletResponseWrapper to solve this solution. This still does not allow to display either XXX-EndTime or YYY-EndTime in the response header.

 @Override public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { long startTime = System.nanoTime(); if(response instanceof HttpServletResponse) { HttpServletResponse httpResp = (HttpServletResponse)response; httpResp.addHeader("Access-Control-Allow-Origin", "*"); httpResp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS"); httpResp.addHeader("Allow", "GET, HEAD, OPTIONS"); httpResp.addHeader("Access-Control-Allow-Headers", "*"); httpResp.addHeader("A-Runtime", Long.toString(startTime)); } OutputStream out = response.getOutputStream(); GenericResponseWrapper wrapper = new GenericResponseWrapper((HttpServletResponse) response); chain.doFilter(request,wrapper); out.write(wrapper.getData()); if(response instanceof HttpServletResponse) { HttpServletResponse httpResp = (HttpServletResponse)response; httpResp.addHeader("XXX-EndTime", Long.toString(System.nanoTime() - startTime)); wrapper.addHeader("YYY-EndTime", Long.toString(System.nanoTime() - startTime)); } out.close(); } 
+6
source share
1 answer

Take a look at the HttpServletResponseWrapper .


OK, then the code:

This code buffers the output (in two models), so adding a header after the pseudo output works. In fact, addHeader could be implemented by output, so we are fortunate that it works. Border register code. With any luck, addHeader will have to be reevaluated.

Mind, when I tried, only getOutputStream is called in my test application. There is a choice that can be made either to select getPrintWriter or to getOutputStream.

 private static class PostponingResponseWrapper extends HttpServletResponseWrapper { private ByteArrayOutputStream bos; private ServletOutputStream outputStream; private StringWriter sw; private PrintWriter printWriter; private boolean usingOutputStream; private boolean usingWriter; public PostponingResponseWrapper (HttpServletResponse response) { super(response); bos = new ByteArrayOutputStream(); outputStream = new ServletOutputStream() { @Override public void write(int b) throws IOException { bos.write(b); } }; sw = new StringWriter(); printWriter = new PrintWriter(sw); } @Override public PrintWriter getWriter() throws IOException { usingWriter = true; LOGGER.info("getWriter usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream); return printWriter; } @Override public void flushBuffer() throws IOException { LOGGER.info("flushBuffer"); } @Override public ServletOutputStream getOutputStream() throws IOException { usingOutputStream = true; LOGGER.info("getOutputStream usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream); ServletOutputStream out = new ServletOutputStream() { @Override public void write(int b) throws IOException { outputStream.write(b); } }; return out; } public void finish() throws IOException { LOGGER.info("finish"); if (usingWriter) { super.getWriter().print(sw.toString()); } else if (usingOutputStream) { super.getOutputStream().write(bos.toByteArray()); } } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpServletResponse = (HttpServletResponse) response; PostponingResponseWrapper responseWrapper = new PostponingResponseWrapper (httpServletResponse); responseWrapper.addHeader("Before", "Already-Worked"); chain.doFilter(request, responseWrapper); responseWrapper.addHeader("After", "And-Now-This"); responseWrapper.finish(); // Writes the actual response } 
+2
source

All Articles