package org.infinispan.rest.logging;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.ext.Provider;
import org.infinispan.util.logging.LogFactory;
import io.netty.channel.ChannelHandlerContext;
/**
* Logging filter that can be used to output requests in a similar fashion to HTTPD log output
*
* @author wburns
* @since 9.0
*/
@Provider
public class RestAccessLoggingHandler implements ContainerResponseFilter, ContainerRequestFilter {
private final static Log log = LogFactory.getLog(RestAccessLoggingHandler.class, Log.class);
private final static String NANO_TIME = "NanoTime";
@Context
private ChannelHandlerContext context;
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
// IP
String remoteAddress = context.channel().remoteAddress().toString();
// Date
String timeString = requestContext.getHeaderString(NANO_TIME);
long startNano;
if (timeString != null) {
startNano = Long.parseLong(requestContext.getHeaderString(NANO_TIME));
} else {
startNano = 0;
}
// Request method | path | protocol
String requestMethod = requestContext.getMethod();
String uri = requestContext.getUriInfo().getPath();
// Status code
int status = responseContext.getStatus();
// Body request size
int requestSize = requestContext.getLength();
// Body response Size - usually -1 so we calculate below
int responseSize = responseContext.getLength();
// Netty doesn't usually set the CONTENT_LENGTH on response - check if we can
if (responseSize == -1 && responseContext.hasEntity()) {
Object entity = responseContext.getEntity();
if (entity instanceof byte[]) {
responseSize = ((byte[]) entity).length;
responseContext.getHeaders().addFirst(HttpHeaders.CONTENT_LENGTH, responseSize);
}
}
// Response time
long responseTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNano);
log.tracef("%s [%s] \"%s %s\" %s %d %d %d ms", remoteAddress, responseTime, requestMethod, uri, status, requestSize,
responseSize, responseTime);
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
int requestSize = requestContext.getLength();
if (requestSize == -1) {
requestSize = requestContext.getEntityStream().available();
requestContext.getHeaders().putSingle(HttpHeaders.CONTENT_LENGTH, Integer.toString(requestSize));
}
// Set the starting time
requestContext.getHeaders().putSingle(NANO_TIME, Long.toString(System.nanoTime()));
}
}