2

我正在使用 log4j 进行日志记录,我有创建一定数量线程的示例代码,我想为每个线程使用不同的日志文件。所以我使用了 PropertyConfigurator.configure() ,它接受一个属性对象。

我已经在我的代码中配置了属性对象,即硬编码,但我想将它加载到代码外部。

现在我想通过属性文件在外部提供所有配置,即不要在代码中硬编码它们并在运行时添加两个属性 -

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() 这样的变量将在运行时被评估。

谁能建议我怎么做

我有三个类-> 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());
}

}

最后我的记录器类是 -->

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;

 }

 }
4

2 回答 2

3

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

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

这是我的工作 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>
于 2014-03-04T07:14:39.750 回答
0

必须在 Runnable 类的 run() 方法中将键 'threadId' [用于 <Routes pattern="$${ctx:threadId}">] 添加到线程上下文映射中,如下所示,

public class SomeClass implements Runnable{

 private int threadID;

 public SomeClass(int threadID){
   this.threadID=threadID;
   }
 @Override
 public void run() {

    ThreadContext.put("threadId", threadID);
    //Some code
    ThreadContext.remove("threadId");
   }
}

另外,必须导入正确的log4j包,如下图。

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

请注意,以下导入将不起作用。LogManager 和 Logger 也必须来自 org.apache.logging.log4j。

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
于 2017-06-01T06:35:06.027 回答