Multithreading 如何以编程方式为多个线程创建单独的Log4j2滚动文件追加器和记录器
我在多个线程上运行TestNG测试(同时在多个设备上运行Appium测试),并希望在不同的文件中的不同线程上编写测试日志。在这里,线程是在测试流开始之前自动创建的 因此,我想以编程方式创建单独的appender和单独的logger,这样每个appender将只连接到自己的线程,然后在一个线程中创建的记录器将只在该线程中创建appender 请让我知道如何一步一步地实现它。首先,这感觉像是一个问题,特别是因为您没有提供任何关于为什么要使用编程解决方案的理由 可以逐个线程地实现单独的日志文件,而无需以编程方式创建记录器和附加器。由于我相信这是一个更为理想的解决方案,我将提供一个演示如何做到这一点 解释 此解决方案将使用和为每个Multithreading 如何以编程方式为多个线程创建单独的Log4j2滚动文件追加器和记录器,multithreading,logging,testng,log4j2,Multithreading,Logging,Testng,Log4j2,我在多个线程上运行TestNG测试(同时在多个设备上运行Appium测试),并希望在不同的文件中的不同线程上编写测试日志。在这里,线程是在测试流开始之前自动创建的 因此,我想以编程方式创建单独的appender和单独的logger,这样每个appender将只连接到自己的线程,然后在一个线程中创建的记录器将只在该线程中创建appender 请让我知道如何一步一步地实现它。首先,这感觉像是一个问题,特别是因为您没有提供任何关于为什么要使用编程解决方案的理由 可以逐个线程地实现单独的日志文件,而无需
线程创建附加器。下面的示例将使用一个简单的FileAppender
,但您可以非常轻松地在RollingFileAppender
中进行交换。由于您没有声明需要为每个线程使用不同的日志级别,下面的示例将不会实现此功能。最后,示例将不使用TestNG,因为它需要设置一些开销;相反,将使用一个简单的类和一个创建两个线程的main
实施示例
log4j2.xml文件:
<?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.txt"
name="appender-${ctx:threadName}">
<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="Thread" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="MyRoutingAppender" />
</Logger>
<Root level="WARN">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class MultiThreadLog4j2SepFilesMain {
//Create a lock to use for synchronizing the getting of the logger
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable(){
public void run() {
//Set up the context before getting logger
ThreadContext.put("threadName", Thread.currentThread().getName());
//Get the logger for this thread
Logger log = null;
synchronized(lock){
log = LogManager.getLogger(Thread.currentThread().getName());
}
//Generate some logs
log.info("here's the first thread");
//Wait a while so that threads interleave
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Generate more logs
log.debug("some debug in first thread");
log.info("finishing first thread");
}}, "Thread.1"); //Use a name that will allow us to use Thread.getName when getting the logger inside the thread
Thread t2 = new Thread(new Runnable(){
public void run() {
//Set up the context before getting logger
ThreadContext.put("threadName", Thread.currentThread().getName());
//Get logger for this thread
Logger log = null;
synchronized(lock){
log = LogManager.getLogger(Thread.currentThread().getName());
}
//Generate some logs
log.info("here's the second thread");
log.debug("some debug in second thread");
}}, "Thread.2"); //Use a name that will allow us to use Thread.getName when getting the logger inside the thread
//Start both threads
t1.start();
t2.start();
}
}