
更新 最新版本的dropwizard支持开箱即用地记录配置
我在尝试使用单独的文件设置Dropwizard(0.8.4)时遇到了相同的问题。我遇到了同样的问题。因此,我进行了更深入的研究,为我找到了一个解决方案(不是最干净的解决方案,但是我似乎无法以不同的方式进行工作)。
问题是
LoggingFactory#configure自动将每个追加程序添加到根目录。这不是很理想,因此需要覆盖。我所做的是:
- 覆盖
LoggingFactory
。
这有点混乱,因为有些事情需要复制:(这是我的实现:
import java.io.PrintStream;import java.lang.management.ManagementFactory;import java.util.Map;import javax.management.InstanceAlreadyExistsException;import javax.management.MBeanRegistrationException;import javax.management.MBeanServer;import javax.management.MalformedObjectNameException;import javax.management.NotCompliantMBeanException;import javax.management.ObjectName;import org.slf4j.LoggerFactory;import org.slf4j.bridge.SLF4JBridgeHandler;import com.codahale.metrics.MetricRegistry;import com.codahale.metrics.logback.InstrumentedAppender;import com.fasterxml.jackson.annotation.JsonIgnore;import com.fasterxml.jackson.annotation.JsonProperty;import com.google.common.collect.ImmutableMap;import ch.qos.logback.classic.Level;import ch.qos.logback.classic.Logger;import ch.qos.logback.classic.LoggerContext;import ch.qos.logback.classic.PatternLayout;import ch.qos.logback.classic.jmx.JMXConfigurator;import ch.qos.logback.classic.jul.LevelChangePropagator;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.Appender;import ch.qos.logback.core.util.StatusPrinter;import io.dropwizard.logging.AppenderFactory;import io.dropwizard.logging.LoggingFactory;public class BetterDropWizardLoggingConfig extends LoggingFactory { @JsonIgnore final LoggerContext loggerContext; @JsonIgnore final PrintStream configurationErrorsStream; @JsonProperty("loggerMapping") private ImmutableMap<String, String> loggerMappings; private static void hijackJDKLogging() { SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install(); } public BetterDropWizardLoggingConfig() { PatternLayout.defaultConverterMap.put("h", HostNameConverter.class.getName()); this.loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); this.configurationErrorsStream = System.err; } private Logger configureLevels() { final Logger root = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); loggerContext.reset(); final LevelChangePropagator propagator = new LevelChangePropagator(); propagator.setContext(loggerContext); propagator.setResetJUL(true); loggerContext.addListener(propagator); root.setLevel(getLevel()); for (Map.Entry<String, Level> entry : getLoggers().entrySet()) { loggerContext.getLogger(entry.getKey()).setLevel(entry.getValue()); } return root; } @Override public void configure(MetricRegistry metricRegistry, String name) { hijackJDKLogging(); final Logger root = configureLevels(); for (AppenderFactory output : getAppenders()) { Appender<ILoggingEvent> build = output.build(loggerContext, name, null); if(output instanceof MappedLogger && ((MappedLogger) output).getLoggerName() != null) { String appenderName = ((MappedLogger) output).getLoggerName(); String loggerName = loggerMappings.get(appenderName); Logger logger = this.loggerContext.getLogger(loggerName); logger.addAppender(build); } else { root.addAppender(build); } } StatusPrinter.setPrintStream(configurationErrorsStream); try { StatusPrinter.printIfErrorsOccured(loggerContext); } finally { StatusPrinter.setPrintStream(System.out); } final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); try { final ObjectName objectName = new ObjectName("io.dropwizard:type=Logging"); if (!server.isRegistered(objectName)) { server.registerMBean(new JMXConfigurator(loggerContext, server, objectName), objectName); } } catch (MalformedObjectNameException | InstanceAlreadyExistsException | NotCompliantMBeanException | MBeanRegistrationException e) { throw new RuntimeException(e); } configureInstrumentation(root, metricRegistry); } private void configureInstrumentation(Logger root, MetricRegistry metricRegistry) { final InstrumentedAppender appender = new InstrumentedAppender(metricRegistry); appender.setContext(loggerContext); appender.start(); root.addAppender(appender); }}如您所知,不幸的是,我不得不复制/粘贴一些私有成员和方法以使事情按预期进行。
我添加了一个新字段:
@JsonProperty("loggerMapping")private ImmutableMap<String, String> loggerMappings;这使我可以为每个记录器配置一个映射。这不是开箱即用的,因为我无法获得名称(dropwizard默认为附加程序名称,非常不便…)
因此,我添加了一个新的Logger,以我为例,由于不同的原因,它也可以替换主机名。为此,我覆盖了旧版本
FileAppenderFactory并实现了自己的接口
MappedLogger。此处的实现:
import com.fasterxml.jackson.annotation.JsonProperty;import com.fasterxml.jackson.annotation.JsonTypeName;import ch.qos.logback.classic.LoggerContext;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.FileAppender;import ch.qos.logback.core.rolling.RollingFileAppender;import io.dropwizard.logging.AppenderFactory;import io.dropwizard.logging.FileAppenderFactory;@JsonTypeName("hostnameFile")public class HostnameFileAppender extends FileAppenderFactory implements AppenderFactory, MappedLogger { private static String uuid = UUID.randomUUID().toString(); @JsonProperty private String name; public void setCurrentLogFilename(String currentLogFilename) { super.setCurrentLogFilename(substitute(currentLogFilename)); } private String substitute(final String pattern) { String substitute = null; try { substitute = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { System.err.println("Failed to get local hostname:"); e.printStackTrace(System.err); substitute = uuid; System.err.println("Using " + substitute + " as fallback."); } return pattern.replace("${HOSTNAME}", substitute); } @Override public void setArchivedLogFilenamePattern(String archivedLogFilenamePattern) { super.setArchivedLogFilenamePattern(substitute(archivedLogFilenamePattern)); } @Override public String getLoggerName() { return name; }}请注意,为了添加新的json类型,您将必须遵循JavaDoc
AppenderFactory(将meta-inf添加到类路径并使新的附加程序可发现)中
到目前为止,到目前为止,我们已经有了一个可以使用记录器映射的配置,我们有一个可以使用可选名称的记录器。
现在,在configure方法中,将这两个绑定在一起:
for (AppenderFactory output : getAppenders()) { Appender<ILoggingEvent> build = output.build(loggerContext, name, null); if(output instanceof MappedLogger && ((MappedLogger) output).getLoggerName() != null) { String appenderName = ((MappedLogger) output).getLoggerName(); String loggerName = loggerMappings.get(appenderName); Logger logger = this.loggerContext.getLogger(loggerName); logger.addAppender(build); } else { root.addAppender(build); } }为了向后兼容,我保留了默认行为。如果未定义名称,则将附加程序添加到根记录器。否则,我将解析键入的记录器,并根据需要向其添加追加器。
最后但并非最不重要的一点是,旧的yaml配置良好:
logging: # The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL. level: INFO loggers: "EVENT" : INFO loggerMapping: # for easier search this is defined as: appenderName -> loggerName rather than the other way around "eventLog" : "EVENT" appenders: - type: console threshold: ALL logFormat: "myformat" - type: hostnameFile # NOTE THE NEW TYPE WITH HOSTNAME RESOLVE currentLogFilename: /Users/artur/tmp/log/my-${HOSTNAME}.log threshold: ALL archive: true archivedLogFilenamePattern: mypattern archivedFileCount: 31 timeZone: UTC logFormat: "myFormat" - type: hostnameFile name: eventLog # NOTE THE APPENDER NAME currentLogFilename: something threshold: ALL archive: true archivedLogFilenamePattern: something archivedFileCount: 31 timeZone: UTC logFormat: "myFormat" - type: hostnameFile currentLogFilename: something threshold: ERROR archive: true archivedLogFilenamePattern: something archivedFileCount: 31 timeZone: UTC logFormat: "myFormat"如您所见,我正在将事件追加器映射到事件记录器。这样,我所有的事件都结束于文件A中,而其他信息结束于其他地方。
我希望这有帮助。可能不是最干净的解决方案,但我不认为Dropwizard当前允许此功能。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)