为了使用 LoggingFeature 记录服务器和客户端请求/响应的自定义日志,您需要创建一个扩展 LoggingFeature 并实现 ContainerRequestFilter、ContainerResponseFilter、ClientRequestFilter、ClientResponseFilter 和 WriterInterceptor 的自定义类。
您需要覆盖 LoggingFeature 方法 public boolean configure(FeatureContext context) 并将您的 CustomLoggingFeature 对象注册到上下文中
@Override
public boolean configure(FeatureContext context) {
context.register(this);
return true;
}
ContainerRequestFilter 和 ContainerResponseFilter 接口具有用于记录服务器请求和响应的方法。
ClientRequestFilter 和 ContainerResponseFilter 接口具有用于记录客户端请求和响应的方法。
另外,您需要实现WriterInterceptor 来记录客户端请求和服务器响应正文。
终于用球衣注册了你的 CustomLoggingFeature 类。
environment.jersey().register(new CustomLoggingFeature(Logger.getLogger(getClass().getName()), Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 8192));
我正在使用 Dropwizard v1.3.5。
这是我的实现。
public class CustomLoggingFeature extends LoggingFeature implements ContainerRequestFilter, ContainerResponseFilter,
ClientRequestFilter, ClientResponseFilter, WriterInterceptor {
private static final boolean printEntity = true;
private static final int maxEntitySize = 8 * 1024;
private final Logger logger = Logger.getLogger("CustomLoggingFeature");
private static final String ENTITY_LOGGER_PROPERTY = CustomLoggingFeature.class.getName();
private static final String NOTIFICATION_PREFIX = "* ";
private static final String REQUEST_PREFIX = "> ";
private static final String RESPONSE_PREFIX = "< ";
private static final String AUTHORIZATION = "Authorization";
private static final String EQUAL = " = ";
private static final String HEADERS_SEPARATOR = ", ";
private static List<String> requestHeaders;
static {
requestHeaders = new ArrayList<>();
requestHeaders.add(AUTHORIZATION);
}
public CustomLoggingFeature(Logger logger, Level level, Verbosity verbosity, Integer maxEntitySize) {
super(logger, level, verbosity, maxEntitySize);
}
@Override
public boolean configure(FeatureContext context) {
context.register(this);
return true;
}
@Override
public void filter(final ClientRequestContext context) {
final StringBuilder b = new StringBuilder();
printHeaders(b, context.getStringHeaders());
printRequestLine(b, "Sending client request", context.getMethod(), context.getUri());
if (printEntity && context.hasEntity()) {
final OutputStream stream = new LoggingStream(b, context.getEntityStream());
context.setEntityStream(stream);
context.setProperty(ENTITY_LOGGER_PROPERTY, stream);
// not calling log(b) here - it will be called by the interceptor
} else {
log(b);
}
}
@Override
public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext) throws IOException {
final StringBuilder b = new StringBuilder();
printResponseLine(b, "Client response received", responseContext.getStatus());
if (printEntity && responseContext.hasEntity()) {
responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(),
MessageUtils.getCharset(responseContext.getMediaType())));
}
log(b);
}
@Override
public void filter(final ContainerRequestContext context) throws IOException {
final StringBuilder b = new StringBuilder();
printHeaders(b, context.getHeaders());
printRequestLine(b, "Server has received a request", context.getMethod(), context.getUriInfo().getRequestUri());
if (printEntity && context.hasEntity()) {
context.setEntityStream(logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType())));
}
log(b);
}
@Override
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) {
final StringBuilder b = new StringBuilder();
printResponseLine(b, "Server responded with a response", responseContext.getStatus());
if (printEntity && responseContext.hasEntity()) {
final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
responseContext.setEntityStream(stream);
requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
// not calling log(b) here - it will be called by the interceptor
} else {
log(b);
}
}
@Override
public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
final LoggingStream stream = (LoggingStream) writerInterceptorContext.getProperty(ENTITY_LOGGER_PROPERTY);
writerInterceptorContext.proceed();
if (stream != null) {
log(stream.getStringBuilder(MessageUtils.getCharset(writerInterceptorContext.getMediaType())));
}
}
private static class LoggingStream extends FilterOutputStream {
private final StringBuilder b;
private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
LoggingStream(final StringBuilder b, final OutputStream inner) {
super(inner);
this.b = b;
}
StringBuilder getStringBuilder(Charset charset) {
// write entity to the builder
final byte[] entity = byteArrayOutputStream.toByteArray();
b.append(new String(entity, 0, Math.min(entity.length, maxEntitySize), charset));
if (entity.length > maxEntitySize) {
b.append("...more...");
}
b.append('\n');
return b;
}
public void write(final int i) throws IOException {
if (byteArrayOutputStream.size() <= maxEntitySize) {
byteArrayOutputStream.write(i);
}
out.write(i);
}
}
private void printHeaders(StringBuilder b, MultivaluedMap<String, String> headers) {
for (String header : requestHeaders) {
if (Objects.nonNull(headers.get(header))) {
b.append(header).append(EQUAL).append(headers.get(header)).append(HEADERS_SEPARATOR);
}
}
int lastIndex = b.lastIndexOf(HEADERS_SEPARATOR);
if (lastIndex != -1) {
b.delete(lastIndex, lastIndex + HEADERS_SEPARATOR.length());
b.append("\n");
}
}
private void log(final StringBuilder b) {
String message = Util.mask(b.toString());
if (logger != null) {
logger.info(message);
}
}
private void printRequestLine(final StringBuilder b, final String note, final String method, final URI uri) {
b.append(NOTIFICATION_PREFIX)
.append(note)
.append(" on thread ").append(Thread.currentThread().getId())
.append(REQUEST_PREFIX).append(method).append(" ")
.append(uri.toASCIIString()).append("\n");
}
private void printResponseLine(final StringBuilder b, final String note, final int status) {
b.append(NOTIFICATION_PREFIX)
.append(note)
.append(" on thread ").append(Thread.currentThread().getId())
.append(RESPONSE_PREFIX)
.append(Integer.toString(status))
.append("\n");
}
private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) throws IOException {
if (!stream.markSupported()) {
stream = new BufferedInputStream(stream);
}
stream.mark(maxEntitySize + 1);
final byte[] entity = new byte[maxEntitySize + 1];
final int entitySize = stream.read(entity);
b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset));
if (entitySize > maxEntitySize) {
b.append("...more...");
}
b.append('\n');
stream.reset();
return stream;
}