我想动态创建一个appender并将其添加到记录器中。但是,这似乎不可能与slf4j。我可以将我的appender添加到log4j记录器,但后来我无法使用slf4j LoggerFactoy检索记录器。
我想做什么:我创建一个测试类(不是jUnit测试)并在构造函数中传递一个记录器供测试类使用。测试类的每个实例都需要它自己的记录器和追加器来保存日志,以便以后可以在HTML报告中使用。
我尝试过(为简单起见,我创建了一个jUnit测试):
import static org.junit.Assert.assertEquals;
import java.util.LinkedList;
import java.util.List;
import org.apache.logging.log4j.core.LogEvent;
import org.junit.Test;
import org.slf4j.helpers.Log4jLoggerFactory;
import ch.fides.fusion.logging.ListAppender;
public class ListAppenderTest {
@Test
public void test() {
String testName = "test1";
// the log messages are to be inserted in this list
List<LogEvent> testLog = new LinkedList<>();
// create log4j logger
org.apache.logging.log4j.core.Logger log4jlogger = (org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager
.getLogger("Test:" + testName);
// create appender and add it to the logger
ListAppender listAppender = new ListAppender("Test:" + testName + ":MemoryAppender", testLog);
log4jlogger.addAppender(listAppender);
// get the slf4j logger
org.slf4j.helpers.Log4jLoggerFactory loggerFactory = new Log4jLoggerFactory();
org.slf4j.Logger testLogger = loggerFactory.getLogger("Test:" + testName);
// test it
final String TEST_MESSAGE = "test message";
testLogger.info(TEST_MESSAGE);
assertEquals(1, testLog.size());
LogEvent logEvent = testLog.get(0);
assertEquals(TEST_MESSAGE, logEvent.getMessage().getFormattedMessage() );
}
}
这是我非常基本的追加者:
package ch.fides.fusion.logging;
import java.util.List;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
public class ListAppender extends AbstractAppender {
private final List<LogEvent> log;
public ListAppender(String name, List<LogEvent> testLog) {
super(name, null, null);
this.log = testLog;
}
@Override
public void append(LogEvent logEvent) {
log.add(new TestLogEvent(logEvent));
}
}
我该怎么做才能让它发挥作用?也许我从错误的角度接近这个,但我想避免创建我自己的记录器类。非常感谢任何帮助。
答案 0 :(得分:8)
通过代码/在运行时访问和操作slf4j上的log4j2:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Log4j2OverSlf4jConfigurator {
final private static Logger LOGGER = LoggerFactory.getLogger(Log4j2OverSlf4jConfigurator.class);
public static void main(final String[] args) {
LOGGER.info("Starting");
LoggerContext loggerContext = (LoggerContext) LogManager.getContext();
Configuration configuration = loggerContext.getConfiguration();
LOGGER.info("Filepath: {}", configuration.getConfigurationSource().getLocation());
// Log4j root logger has no name attribute -> name == ""
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");
rootLoggerConfig.getAppenders().forEach((name, appender) -> {
LOGGER.info("Appender {}: {}", name, appender.getLayout().toString());
// rootLoggerConfig.removeAppender(a.getName());
});
rootLoggerConfig.getAppenderRefs().forEach(ar -> {
System.out.println("AppenderReference: " + ar.getRef());
});
// adding appenders
configuration.addAppender(null);
}
}
参考:https://logging.apache.org/log4j/2.x/manual/customconfig.html
答案 1 :(得分:3)
我认为你有类似我们的情景。生产中更复杂的日志记录,但在JUnit测试期间更简单,因此我们可以断言没有错误。
如果您使用的是log4j2,则使用构建器的解决方案更清晰> 2.4(但是,不支持Java6),但这是我使用log4j2 2.3的那个:
@Test
public void testClass() {
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
Configuration configuration = loggerContext.getConfiguration();
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("");
ListAppender listAppender = new ListAppender("testAppender");
rootLoggerConfig.addAppender(listAppender, Level.ALL, null);
new TestClass(); //this is doing writing an error like org.slf4j.LoggerFactory.getLogger(TestClass.class).error("testing this");
assertEquals(1, listAppender.getEvents().size());
}
重要的是要注意我们需要通过&#34; false&#34;在调用getContext时,否则它似乎没有得到与slf4j相同的上下文。
答案 2 :(得分:1)
如果还有其他人迷惑不解,则使用slf4j 1.7.26版时,需要构建器模式,该模式与接受的答案有关。以下实现可在Java 8+和Scala 2.13中使用(与lqbweb的答案略有不同):
Java:
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.LoggerContext
LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false)
Configuration configuration = loggerContext.getConfiguration()
LoggerConfig rootLoggerConfig = configuration.getLoggerConfig("")
PatternLayout.Builder layoutBuilder = PatternLayout.newBuilder()
layoutBuilder.withPattern("%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n")
RandomAccessFileAppender.Builder<?> appenderBuilder =
(RandomAccessFileAppender.Builder<?>) RandomAccessFileAppender
.newBuilder()
appenderBuilder.setLayout(layoutBuilder.build())
appenderBuilder.withBufferedIo(true)
appenderBuilder.setFileName(logFile.getAbsolutePath)
appenderBuilder.setName("OutputDirFileLogger")
RandomAccessFileAppender appender = appenderBuilder.build()
appender.start() // important to make the appender usable instantly
rootLoggerConfig.addAppender(appender, Level.DEBUG, null)
scala:
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.LoggerContext
val loggerContext = LogManager.getContext(false).asInstanceOf[LoggerContext]
val configuration: Configuration = loggerContext.getConfiguration
val rootLoggerConfig: LoggerConfig = configuration.getLoggerConfig("")
val layoutBuilder: PatternLayout.Builder = PatternLayout.newBuilder()
layoutBuilder.withPattern("%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n")
val appenderBuilder: RandomAccessFileAppender.Builder[_] = RandomAccessFileAppender
.newBuilder()
.asInstanceOf[RandomAccessFileAppender.Builder[_]]
appenderBuilder.setLayout(layoutBuilder.build())
appenderBuilder.withBufferedIo(true)
appenderBuilder.setFileName(logFile.getAbsolutePath)
appenderBuilder.setName("OutputDirFileLogger")
val appender: RandomAccessFileAppender = appenderBuilder.build()
appender.start()
rootLoggerConfig.addAppender(appender, Level.DEBUG, null)
答案 3 :(得分:0)
Daniele,一个ListAppender存在于Log4J-2.0(包org.apache.logging.log4j.test.appender
)中。它是发行版的一部分,但它位于log4j-core-tests jar中。它主要用于JUnit测试。 JUnit测试源还提供了示例配置,显示了如何使用此ListAppender进行配置。
示例配置看起来像这样:
<Configuration status="warn" packages="org.apache.logging.log4j.test">
<Appenders>
<List name="MyList">
</List>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="MyList"/>
</Root>
</Loggers>
</Configuration>