如何以编程方式为多个线程创建单独的Log4j2滚动文件附加器和记录器 [英] How to create separate Log4j2 rolling file appenders and loggers programatically for multiple threads

查看:132
本文介绍了如何以编程方式为多个线程创建单独的Log4j2滚动文件附加器和记录器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在多个线程上运行TestNG测试(同时在多个设备上运行Appium测试),并希望将测试日志写在不同文件中的不同线程上.这里的线程是在测试流程开始之前自动创建的.

I am running my TestNG tests on multiple threads (Appium tests on multiple devices simultaneously) and want to write the test logs on different threads in different files. Here the threads are created automatically before the start of the test flow.

因此,我想以编程方式创建单独的附加程序和单独的记录器,以便将每个附加器仅附加到其自己的线程,然后在一个线程中创建的记录器将仅在该线程中创建附加器.

So I want to create separate appender and separate logger programatically so that each appender would be attached to its own thread only and then the loggers created in one thread would have the appender created in that thread only.

请让我知道如何逐步实现它.

Please let me know how to achieve it step by step.

推荐答案

首先,这感觉像是 XY问题因为您没有提供有关为什么要使用程序化解决方案的任何理由.

First, this feels like an XY Problem especially because you have not provided any reasoning as to why you want to go with a programmatic solution.

无需编程创建记录器和附加程序,就可以在每个线程的基础上实现单独的日志文件.由于我相信这是一个最佳解决方案,因此我将提供一个演示如何完成的演示.

It is possible to achieve separate log files on a thread by thread basis without programmatically creating loggers and appenders. Since I believe this to be a more optimal solution I will provide a demo of how it can be done.

说明

此解决方案将使用 RoutingAppender ThreadContext 为每个Thread创建附加程序.以下示例将使用简单的FileAppender,但是您可以非常轻松地交换RollingFileAppender.由于您并未声明对每个线程使用不同的日志级别有任何要求,因此以下示例将不会实现此功能.最后,该示例将不使用TestNG,因为它需要设置一些开销.而是使用一个简单的类,该类具有创建两个线程的main.

This solution will use the RoutingAppender and ThreadContext to create appenders for each Thread. The example that follows will use a simple FileAppender but you can swap in a RollingFileAppender very easily. Since you did not state that you have any requirement to use different log levels for each thread the following example will not implement this feature. Finally, the example will not use TestNG as it has some overhead to set up; instead a simple class with a main that creates two threads will be used.

示例实现

log4j2.xml文件:

log4j2.xml file:

<?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>

使用2个并发线程生成日志的Java类:

Java class that generates logs using 2 concurrent threads:

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();
    }
}

这篇关于如何以编程方式为多个线程创建单独的Log4j2滚动文件附加器和记录器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆