为每个创建的线程使用不同的日志文件 [英] Using different Log files for every thread created
问题描述
我正在使用log4j进行日志记录,我有一些示例代码可以创建一定数量的线程,我想为每个线程使用不同的日志文件。
所以我使用PropertyConfigurator.configure()接受一个属性对象。
I am working on logging with log4j, i have sample code which creats certain number of threads , i want to use different log files for each threads. so I have use the PropertyConfigurator.configure() which takes a property object.
我在我的代码中配置了属性对象,即硬编码,但我想要将其加载到代码外部。
I have configured the property object in my code i.e hardcoded , but I want to load it external to code.
现在我想通过属性文件从外部提供所有配置,即不要在代码中对它们进行硬编码,并在运行时添加两个属性 -
Now I want to provide all the configurations externally through a property file i.e not to hardcode them in code and at runtime add the two properties -
props.setProperty("log4j.logger."+"Thread" +
Thread.currentThread().getName(),"DEBUG, file");
和
props.setProperty("log4j.appender.file.File",
"/home/ekhaavi/workspace/TEST_2/ThreadHandler"+
Thread.currentThread().getName()+".log");
因为这些变量如Thread.currentThread()。getName()将在运行时得到评估。
since these variables like Thread.currentThread().getName() will get evaluated at runtime.
任何人都可以建议我怎么做
can anyone suggest me how to do it
我有三个类 - > MainClass,Parser(Thread class) ,包中的LoggerClass
I have three class --> MainClass, Parser(Thread class), LoggerClass in package
import java.util.HashMap;
import java.util.Map;
public class MainClass {
private static final org.apache.log4j.Logger log = LoggerClass.getLogger(MainClass.class);
public static void main(String args[]){
Map map = new HashMap();
map.put("Subject", "Math");
log.info("The value of the map is " + map.toString());
for(int ii=0; ii< 3; ii++){
Parser th = new Parser(ii);
}
}
}
package com.test.log4j.conf;
public class Parser implements Runnable{
private org.apache.log4j.Logger log;
Parser(){
Thread th = new Thread(this);
th.start();
}
@Override
public void run() {
log = LoggerClass.getThreadLogger("Thread" + Thread.currentThread().getName());
log.info("------dagdjlagdjgasdjljgljg");
System.out.println("The thread is " + Thread.currentThread().getName());
}
}
最后我的记录器类是 - >
and finally my logger class is -->
import java.util.Properties;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public abstract class LoggerClass {
public static Logger getLogger(Class clazz){
org.apache.log4j.Logger log = Logger.getLogger(clazz);
Properties props=new Properties();
props.setProperty("log4j.appender.file","org.apache.log4j.RollingFileAppender");
props.setProperty("log4j.appender.logfile","org.apache.log4j.DailyRollingFileAppender");
props.setProperty("log4j.appender.logfile.DatePattern","'.'yyyy-MM-dd");
props.setProperty("log4j.appender.logfile.layout","org.apache.log4j.PatternLayout");
props.setProperty("log4j.appender.logfile.layout.ConversionPattern","%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n");
props.setProperty("log4j.appender.logfile.File","/home/ekhaavi/workspace/TEST_2/mylogfile.log");
props.setProperty("log4j.logger.com.com.test.log4j.conf","INFO, logfile");
PropertyConfigurator.configure(props);
return log;
}
public static Logger getThreadLogger(String str){
org.apache.log4j.Logger log = Logger.getLogger(str);
Properties props=new Properties();
props.setProperty("log4j.appender.file","org.apache.log4j.DailyRollingFileAppender");
props.setProperty("log4j.appender.file.DatePattern","'.'yyyy-MM-dd");
props.setProperty("log4j.appender.file.layout","org.apache.log4j.PatternLayout");
props.setProperty("log4j.appender.file.File","/home/ekhaavi/workspace/TEST_2/ThreadHandler"+Thread.currentThread().getName()+".log");
props.setProperty("log4j.appender.file.layout.ConversionPattern","%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n");
props.setProperty("log4j.logger."+"Thread" + Thread.currentThread().getName(),"DEBUG, file");
PropertyConfigurator.configure(props);
return log;
}
}
推荐答案
对于log4j v2,您可以使用RoutingAppender动态路由消息。您可以将键'threadId'的值放入ThreadContext映射中,然后将此id用作文件名的一部分。有一个例子我很容易应用于你的目的。请参阅 http://logging.apache.org/log4j/2.x/ faq.html#separate_log_files
For log4j v2 you can use RoutingAppender to dynamically route messages. You can put value for key 'threadId' into the ThreadContext map and then use this id as a part of file name. There is an example which I have easily applied for the same purpose as yours. See http://logging.apache.org/log4j/2.x/faq.html#separate_log_files
在将值放入ThradContext映射时要注意:子线程会自动继承其父级的映射诊断上下文的副本。
因此,如果您将键'threadId'的值放入父线程并最终从中创建多个线程,那么所有子线程将继承'threadId'值的值。我无法通过再次使用put()简单地覆盖此值 - 您需要使用ThreadContext.clear()或从线程上下文映射中显式删除()值。
Be aware when putting values into ThradContext map: "A child thread automatically inherits a copy of the mapped diagnostic context of its parent." So if you have put a value for key 'threadId' into the parent thread and eventually created multiple threads from it, then all child threads will inherit the value of 'threadId' value. I was no able to simply override this value by using put() one more time - you need to use ThreadContext.clear() or explicitly remove() the value from thread context map.
这是我的工作log4j.xml:
Here is my working 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>
这篇关于为每个创建的线程使用不同的日志文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!