我的测试自动化项目存在日志问题。我使用log4j2 logger和FileAppender。我使用它的方式是:
Logger logger = (Logger) LogManager.getLogger(loggerName);
Appender appender = FileAppender.newBuilder()
.withAppend(false)
.withBufferedIo(true)
.withFileName(DIR_NAME + File.separator + loggerName + ".log")
.withIgnoreExceptions(false)
.withImmediateFlush(true)
.withLocking(false)
.withLayout(PatternLayout.newBuilder().withPattern("%d{HH:mm:ss.SSS} [%-5level] %msg%n").withCharset(Charset.forName("UTF-8")).build())
.withName(loggerName)
.build();
appender.start();
logger.addAppender(appender);
当我进行单一测试时,它会起作用。所有数据都在控制台中可见,创建文件并在文件中写入测试日志。如果测试并行运行 - 在不同的线程中出现问题。
在这种情况下,会创建两个不同的记录器和文件追加器。还会创建来自两个文件追加程序的日志文件,并且在控制台中可以看到来自两个测试的日志。一切似乎都很好,但每次其中一个日志文件为空。空日志属于稍后开始的测试。
我怀疑缓存有问题。第一个文件追加器保存所有用于写入的高速缓存,因此第二个无法写入。我对吗?这是什么解决方案?
谢谢。
答案 0 :(得分:0)
您应该能够在不使用编程配置的情况下实现您的目标。有很多理由不以编程方式配置log4j2,但在我看来,最好的原因是,这样做会使你的代码依赖于log4j2的不公共API的一部分。这意味着如果log4j2的实现发生变化,您的代码也必须改变。从长远来看,这为您创造了更多的工作。
因此,考虑到这一点,我将提供一个演示如何使用XML配置文件设置log4j2,以便为每个测试生成单独的日志。我假设,因为在您的问题中未指定,您的目标是使用Test
注释为每个方法创建一个日志,并且每个方法都是并行执行的。
首先,这是我的TestNG课程:
package testpkg;
import java.lang.reflect.Method;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class NewTest {
private static final Logger log = LogManager.getLogger();
@BeforeMethod
public void setThreadName(Method method){
ThreadContext.put("threadName", method.getName());
}
@Test
public void test1() {
log.info("This is the first test!");
log.warn("Something may be wrong, better take a look.");
}
@Test
public void test2() {
log.info("Here's the second test!");
log.error("There's a problem, better fix it");
}
}
正如您在此处所见,我有两个Test
方法和一个名为BeforeMethod
的{{1}}。显然,setThreadName
方法在每个setThreadName
方法之前执行。它使用即将运行的方法的名称将名为Test
的密钥放入log4j2 threadName
。这将用作log4j2配置文件中日志文件名的一部分。
这是log4j2.xml文件:
ThreadContext
正如您所见,我已设置配置文件以使用<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Routing name="MyRoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route>
<File
fileName="logs/${ctx:threadName}.log"
name="appender-${ctx:threadName}"
append="false">
<PatternLayout>
<Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="testpkg" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="MyRoutingAppender" />
</Logger>
<Root level="WARN">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
在运行时根据RoutingAppender
密钥ThreadContext
和{{1}动态生成appender }}也用于threadName
的{{1}}属性。
这是我的testNG配置文件:
threadName
正如您在此处所见,我已对其进行了设置,以便我班级中的每个fileName
方法并行运行。
执行时会产生以下控制台输出:
FileAppender
您可以清楚地看到两种方法的输出是交错的,因此我们知道这些方法确实是并行运行的。
测试类的执行还会按预期创建两个日志文件。它们被命名为test1.log和test2.log
以下是他们的内容:
test1.log:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="My suite" parallel="methods" thread-count="5" verbose="1">
<test name="testpkg" >
<classes>
<class name="testpkg.NewTest" />
</classes>
</test>
</suite>
test2.log:
Test
所以我们在这里看到,正如预期的那样,第一种方法的日志转到了test1.log,第二种方法的日志转到了test2.log
享受!