问题
We're trying to add a custom http header to dropwizard access logs. We tried dropwizard 0.9.1 and 0.9.2, but can't find a way to do this. We noticed the following:
- server.requestlogs.appenders[file].logFormat is being ignored. It always logs using the common logging format.
- logging.appenders[file].logFormat is honoured, but web specific stuff results in %PARSER_ERROR[..] for things like %header{HEADER-NAME}, %A, etc.
Is there a way to log such information?
回答1:
It is possible to use a custom org.eclipse.jetty.server.RequestLog
implementation, which can be registered to jetty by extending io.dropwizard.jetty.RequestLogFactory
and replacing the dropwizard implementation in the ServerFactory. Here one possible implementation:
import ch.qos.logback.classic.*;
import ch.qos.logback.classic.spi.*;
import ch.qos.logback.core.*;
import ch.qos.logback.core.spi.*;
import com.google.common.collect.ImmutableList;
import io.dropwizard.jetty.*;
import io.dropwizard.logging.*;
import org.eclipse.jetty.server.*;
import org.slf4j.LoggerFactory;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.Enumeration;
import java.util.TimeZone;
public class CustomRequestLogFactory extends RequestLogFactory {
@NotNull
private TimeZone timeZone = TimeZone.getTimeZone("UTC");
@Valid
@NotNull
private ImmutableList<AppenderFactory> appenders = ImmutableList.<AppenderFactory>of(
new ConsoleAppenderFactory()
);
private static class RequestLogLayout extends LayoutBase<ILoggingEvent> {
@Override
public String doLayout(ILoggingEvent event) {
return event.getFormattedMessage() + CoreConstants.LINE_SEPARATOR;
}
}
private static class CustomRequestLog extends Slf4jRequestLog {
private static Logger logger = (Logger) LoggerFactory.getLogger(CustomRequestLog.class);
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>() {
@Override
protected StringBuilder initialValue() {
return new StringBuilder(256);
}
};
public CustomRequestLog(AppenderAttachableImpl<ILoggingEvent> appenders,
TimeZone timeZone) {
super(appenders, timeZone);
}
@Override
public void log(Request request, Response response) {
StringBuilder buf = _buffers.get();
buf.setLength(0);
buf.append(request.getServerName()).append('\n');
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String header = headers.nextElement();
buf.append(header).append('=')
.append(request.getHeader(header)).append('\n');
}
try {
write(buf.toString());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
public RequestLog build(String name) {
final Logger logger = (Logger) LoggerFactory.getLogger("http.request");
logger.setAdditive(false);
final LoggerContext context = logger.getLoggerContext();
final RequestLogLayout layout = new RequestLogLayout();
layout.start();
final AppenderAttachableImpl<ILoggingEvent> attachable =
new AppenderAttachableImpl<>();
for (AppenderFactory output : this.appenders) {
attachable.addAppender(output.build(context, name, layout));
}
return new CustomRequestLog(attachable, timeZone);
}
}
Set the RequestLogFactory in the ServerFactory:
@Override
public void run(ApplicationConfiguration configuration,
Environment environment) {
...
((DefaultServerFactory) configuration.getServerFactory())
.setRequestLogFactory(new CustomRequestLogFactory());
}
来源:https://stackoverflow.com/questions/35487749/logging-some-request-headers-with-dropwizard