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)
@havexz的方法非常好:将所有内容写入同一个日志文件并使用嵌套的诊断上下文.
如果您关心的是几个JVM写入同一个FileAppender,那么我建议两件事:
在谨慎模式下,即使存在可能在不同主机上运行的不同JVM中运行的其他FileAppender实例,FileAppender也会安全地写入指定文件.