java – Dropwizard不会将自定义记录器记录到文件中
|
我有一个dropwizard应用程序,我将logger appender配置为文件,如下所示: logging:
level: INFO
loggers:
"mylogger": INFO
"com.path.to.class": INFO
appenders:
- type: file
currentLogFilename: .logs/mylogs.log
archivedLogFilenamePattern: .logs/archive.%d.log.gz
archivedFileCount: 14
并且,在我的应用中创建了记录器: import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Logger OpLogger = LoggerFactory.getLogger("mylogger");
(and)
private final Logger ClassLogger = LoggerFactory.getLogger(pathToClass.class);
在main()中进行一些测试记录: OpLogger.info("test 1");
ClassLogger.info("test 2);
应用程序启动并运行没有问题;但我没有得到任何日志(除了Jetty访问日志,当然,正确打印到mylogs.log),无论是在stdout还是在mylogs.log文件中.相反,如果我删除configuration.yml中的记录器配置,我会将所有日志打印到stdout. 解决方法更新最新版本的dropwizard支持开箱即用的日志配置我遇到了同样的问题,尝试使用单独的文件设置Dropwizard(0.8.4).我遇到了同样的问题.所以我挖得更深一些,为我找到了一个解决方案(不是最干净但我似乎无法以不同的方式工作). 问题是LoggingFactory #configure会自动将每个appender添加到root.这不是很理想,所以需要覆盖.我做的是: >覆盖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默认的appender名称,非常不方便……) 所以我添加了一个新的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类型,您必须遵循AppenderFactory中的JavaDoc(将Meta-inf添加到类路径并使新的appender可被发现) 到目前为止,我们现在有了一个可以接收记录器映射的配置,我们有一个可以选择名称的记录器. 在配置方法中,我现在将这两者结合在一起: for (AppenderFactory output : getAppenders()) {
Appender<ILoggingEvent> build = output.build(loggerContext,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);
}
}
为了向后兼容,我保留了默认行为.如果没有定义名称,则appender将添加到根记录器中.否则我解析输入的记录器并根据需要添加appender. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
