如何在不同的日志文件中记录多个线程?

Tim*_*Tim 7 java multithreading log4j

我有一个JAVA类,它启动具有唯一ID的各种线程.每个线程都应该登录到以ID.log命名的唯一日志文件.

因为我只在运行时获取唯一ID,所以我必须以编程方式配置Log4J:

// Get the jobID
myJobID = aJobID;
// Initialize the logger
myLogger = Logger.getLogger(myJobID);
FileAppender myFileAppender;
try
{
    myFileAppender = new FileAppender(new SimpleLayout(), myJobID + ".log", false);
    BasicConfigurator.resetConfiguration();
    BasicConfigurator.configure(myFileAppender);
} catch (IOException e1) {
// TODO Auto-generated catch block
    e1.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我按顺序启动作业,这可以正常工作 - 但是当我同时启动2个线程(同一类)时,会创建两个日志,但日志会混淆:第二个线程会记录到第一个和第二个日志中.

我怎样才能确保每个实例都是唯一的?我已经尝试为每个记录器实例提供一个唯一的名称,但它没有改变任何东西.

Cek*_*eki 13

Logback有一个名为SiftingAppender的特殊appender ,它为您描述的问题类型提供了一个非常好的解决方案.SiftingAppender可用于根据任何运行时属性(包括线程ID)分离(或筛选)日志记录.


小智 9

对于log4j v2,您可以使用RoutingAppender动态路由消息.您可以将键'threadId'的值放入ThreadContext映射中,然后将此id用作文件名的一部分.有一个例子我很容易应用于你的目的.请参阅http://logging.apache.org/log4j/2.x/faq.html#separate_log_files

在将值放入ThradContext映射时要注意:"子线程会自动继承其父级的映射诊断上下文的副本." 因此,如果您已将键'threadId'的值放入父线程并最终从其创建多个线程,则所有子线程将继承'threadId'值的值.我无法通过再次使用put()来简单地覆盖此值 - 您需要使用ThreadContext.clear()或从线程上下文映射中显式删除()值.

这是我的工作log4j.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN">
    <properties>
        <property name="logMsgPattern">%d{HH:mm:ss} %-5level - %msg%n</property>
        <property name="logDir">test logs</property><!-- ${sys:testLogDir} -->
    </properties>
    <appenders>
         <Console name="Console" target="SYSTEM_OUT">           
            <PatternLayout pattern="${logMsgPattern}"/>
         </Console>

        <Routing name="Routing">
                    <Routes pattern="$${ctx:threadId}">             
                        <Route>
                            <RollingFile name="RollingFile-${ctx:threadId}" fileName="${logDir}/last-${ctx:threadId}.log" filePattern="${logDir}/%d{yyyy-MM-dd}/archived_%d{HH-mm}-${ctx:threadId}.log">
                                    <PatternLayout pattern="${logMsgPattern}"/>
                                    <Policies>
                                <OnStartupTriggeringPolicy />
                            </Policies> 
                    </RollingFile>
                        </Route>
                    </Routes>
            </Routing>  
    </appenders>

    <loggers>               
        <root level="debug">
            <appender-ref ref="Console" level="debug" />
            <appender-ref ref="Routing" level="debug"/>
        </root>                     
    </loggers>  
</configuration>
Run Code Online (Sandbox Code Playgroud)


Bri*_*zel 5

@havexz的方法非常好:将所有内容写入同一个日志文件并使用嵌套的诊断上下文.

如果您关心的是几个JVM写入同一个FileAppender,那么我建议两件事:

在谨慎模式下,即使存在可能在不同主机上运行的不同JVM中运行的其他FileAppender实例,FileAppender也会安全地写入指定文件.