简体   繁体   English

无法使用 log4j2 为不同的线程写入不同的日志

[英]unable to write into different logs for different threads using log4j2

I'm trying to write logs into different files for each Thread/ThreadGroup.我正在尝试为每个线程/线程组将日志写入不同的文件。 My code is creating different files for each thread, but it writing all other threads logs into one file.我的代码为每个线程创建不同的文件,但它将所有其他线程写入一个文件中。

MainTest.java主测试.java

public class MainTest {
    public static void main(String[] args) {
        ThreadGroup tg1 = new ThreadGroup("Group A");

        Thread t1 = new Thread(tg1, new LoggingTest(), "t1");
        t1.start();

        Thread t2 = new Thread(tg1, new LoggingTest(), "t2");
        t2.start();

        //
        Thread t3 = new Thread(new LoggingTest(),"t3");
        t3.start();
    }
}

LoggingTest.java记录测试.java

public class LoggingTest implements Runnable {
    private static final Logger logger      = LogManager.getLogger(LoggingTest.class);
    private static final String logFilePath = "/output/logs/";
    private static final String pattern     = "%d{dd MMM yyyy HH:mm:ss.SSS} (%F:%L) - %m%n";

    public void run() {
        Thread runner         = Thread.currentThread();
        
        LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
        try {
            URL configFile    = LoggingTest.class.getResource("/log4j2.properties");
            context.setConfigLocation(configFile.toURI());
        }catch(Exception e) {
            e.printStackTrace();
        }
        
        LoggerContext ctx     = (LoggerContext) LogManager.getContext(false);
        FileAppender appender = null;
        try {
            appender = FileAppender
                    .newBuilder()
                    .setName("Name")
                    .setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
                    .withFileName(logFilePath + runner.getName() + ".log")
                    .build();
        } catch (Exception e) {
            logger.error("error -> "+e);
        }
        
        if (appender != null) {
            if ( runner.getThreadGroup().getParent() != null )
            {
                appender.addFilter( new ThreadGroupFilter( runner.getThreadGroup() ) );
            }
            else
            {
                appender.addFilter( new ThreadFilter( runner ) );
            }
            appender.start();
            ctx.getRootLogger().addAppender(appender);
            ctx.updateLoggers();
        }

        logger.info("info msg");
        logger.debug("debug msg");
        logger.error("error msg");

        if ( appender != null ) {
            ctx.getRootLogger().removeAppender(appender);
            ctx.updateLoggers();
            appender.stop();
        }
    }
}

Here I created couple of filter classes for both Thread & ThreadGroup.在这里,我为 Thread 和 ThreadGroup 创建了几个过滤器类。 But seems like these are not working properly.但似乎这些无法正常工作。 ThreadGroupFilter.java ThreadGroupFilter.java

import org.apache.logging.log4j.core.Filter;  

public class ThreadGroupFilter implements Filter {
        
        private final ThreadGroup filterThreadGroup;
    
        public ThreadGroupFilter( ThreadGroup filterThreadGroup ) {
            this.filterThreadGroup = filterThreadGroup;
        }
    
        @Override
        public Result filter(LogEvent event) {
            if ( Thread.currentThread().getThreadGroup() != filterThreadGroup )
                return Filter.Result.DENY;
    
            return Filter.Result.NEUTRAL;
        }
    }

ThreadFilter.java ThreadFilter.java

public class ThreadFilter implements Filter {
    private final Thread filterThread;

    public ThreadFilter( Thread filterThread ) {
        this.filterThread = filterThread;
    }
    
    @Override
    public Result filter(LogEvent event) {
        if ( Thread.currentThread() != filterThread )
            return Filter.Result.DENY;

        return Filter.Result.NEUTRAL;
    }
}

log4j2.properties log4j2.properties

name=PropertiesConfig
property.basePath = ../logs

appenders = console

appender.console.type = Console
appender.console.name = consoleLogger
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %5p [%c] [%t] (%F:%L) - %m%n

rootLogger.level = debug
rootLogger.appenderRefs = console
rootLogger.appenderRef.stdout.ref = consoleLogger

I'm expecting multiple log files for each Thread/ThreadGroup.我期望每个线程/线程组有多个日志文件。 But I'm ended up with multiple log files for each Thread and all threads logs into one file.但是我最终得到了每个线程的多个日志文件,并且所有线程都记录到一个文件中。

Thank you in advance.先感谢您。

Each of your threads calls LoggerContext#setConfigLocation , which causes a reconfiguration of Log4j2.您的每个线程都调用LoggerContext#setConfigLocation ,这会导致重新配置 Log4j2。 The reconfiguration removes all the appenders you added programmatically.重新配置会删除您以编程方式添加的所有附加程序。 That is why you end up with a single appender.这就是为什么你最终只有一个 appender。

Remark that you do not need programmatic configuration to have a different file appender per thread.请注意,您不需要编程配置每个线程都有不同的文件附加程序。 You can just use the RoutingAppender as in this question .您可以像在这个问题中那样使用RoutingAppender

Edit : If you really want to use programmatic configuration (which is discouraged for compatibility reasons), you also need to use a unique name for each appender, otherwise they will be silently ignored (the Logger#addAppender method you use is not part of the public API, cf. javadoc , so errors are not reported).编辑:如果你真的想使用编程配置(出于兼容性原因不鼓励这样做),你还需要为每个附加程序使用一个唯一的名称,否则它们将被默默地忽略(你使用的Logger#addAppender方法不是public API,cf. javadoc ,因此不会报告错误)。

move this piece of code from LoggingTest to MainTest将这段代码从 LoggingTest 移到 MainTest

LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
try {
    URL configFile    = LoggingTest.class.getResource("/log4j2.properties");
    context.setConfigLocation(configFile.toURI());
}catch(Exception e) {
    e.printStackTrace();
}

And minor modifications at Appender configuration.并对 Appender 配置进行了细微修改。

FileAppender appender = null;
String appenderName = (runner.getThreadGroup() != null) ? "appender_"+runner.getThreadGroup().getName() : "appender_"+runner.getName();
try {
    appender = FileAppender
            .newBuilder()
            .setName(appenderName)
            .setLayout(PatternLayout.newBuilder().withPattern(pattern).build())
            .withFileName(logFilePath + appenderName + ".log")
            .build();
} catch (Exception e) {
    logger.error("error -> "+e);
}

Thanks for the solution Poitr P. Karwasz感谢Poitr P. Karwasz的解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM