简体   繁体   中英

Determine request/response size metrics in Jersey RequestEventListener

We want to measure the request and response sizes of our API endpoints. As it recommended to determine the duration with a RequestEventListener we took that approach.

Using the inspector, we can see that the requestEvent contains a property containerResponse.messageContext.commitingOutputStream.adoptedOutput.delegate.outputStream.count which contains the actual response size in bytes. However, we cannot access this field using public methods and fields. The accessible method containerResponse.getLength() always returns -1 . The same for containerRequest.getLength() .

How can we access the actual request and response sizes, preferably without reflection?

private class EndPointPerformanceFilter implements RequestEventListener {
    private long start;

    @Override
    public void onEvent(final RequestEvent requestEvent) {
        switch (requestEvent.getType()) {
            case START:
                start = timeProvider.currentTimeMillis();
                break;
            case FINISHED:
                final long duration = timeProvider.currentTimeMillis() - start;

                final ContainerRequest containerRequest = requestEvent.getContainerRequest();
                final ContainerResponse containerResponse = requestEvent.getContainerResponse();

                System.out.println("Req: [" + containerRequest.getLength() + "] Rep: [" + containerResponse.getLength() +"]");
                break;
        }
    }
}

I tried to do the exact same thing before. I never found a solution that involved getting the data directly from Jersey. I just implemented a WriterInterceptor where I set the OutputStream to Apache Commons' CountingOutputStream . Then got the count after the writer was finished.

I don't have the exact implementation on hand, but reproducing the functionality, it pretty much goes like this

@Provider
public class ContentLengthLoggingProvider implements ReaderInterceptor, WriterInterceptor {

    private static final Logger logger = Logger.getLogger(ContentLengthLoggingProvider.class.getName());
    private static final String REQUEST_LENGTH_PROPERTY = "Request.Content.Length";

    @Override
    public void aroundWriteTo(WriterInterceptorContext writerContext) 
            throws IOException, WebApplicationException {

        CountingOutputStream outputStream 
                = new CountingOutputStream(writerContext.getOutputStream());
        writerContext.setOutputStream(outputStream);

        writerContext.proceed();

        long responseCount = outputStream.getCount();
        String requestCount = (String)writerContext.getProperty(REQUEST_LENGTH_PROPERTY);
        String log = "Req: [" + requestCount + "] Rep: [" + responseCount +"]";
        logger.info(log);
    }

    @Override
    public Object aroundReadFrom(ReaderInterceptorContext readerContext) 
            throws IOException, WebApplicationException {
        String requestLength = readerContext.getHeaders().getFirst(HttpHeaders.CONTENT_LENGTH);
        readerContext.setProperty(REQUEST_LENGTH_PROPERTY, requestLength);
        return readerContext.proceed();
    }  
}

This is the dependency I used

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

I think Guava has a similar CountingOutputStream class. So if you are using Guava, you can also use that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM