`

用Log4j实现线程独立日志

阅读更多

需求:

      在一个项目里,我使用Log4j生成日志,我不希望任务线程组各个线程都记录在同一个日志里,那样太乱了,而是单独生成日志记录。这样的话,需要针对每个线程创建Logger实例,实例名应对应线程名,而每个Logger实例的文件名应分别对应于实例名或者线程名。

 

思想:

      在网上搜了很多文章后,我还是找不到在配置文件里根据Logger实例以变量形式设置动态File的方法。那么只能打源码的主意了。打开 org.apache.log4j.DailyRollingFileAppender 的源码简单分析了一下:DailyRollingFileAppender 继承了FileAppender类,它个构造方法是DailyRollingFileAppender (Layout layout, String filename, String datePattern),那么可以写个自定义的Appender继承DailyRollingFileAppender,在构造方法里直接将filename设成当前线程名;再将Appender、layout的参数设置及与Logger的绑定封装在一个静态方法里就可以达到目的了。

 

具体代码:

 

自定义Appender

package threadlogger.appender;

import java.io.File;
import java.io.IOException;

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Layout;

/**
 * @author Kevin Kwok
 */
public class ThreadSeperateDailyRollingFileAppender extends
        DailyRollingFileAppender
{
    public ThreadSeperateDailyRollingFileAppender() {}
    
    public ThreadSeperateDailyRollingFileAppender(Layout layout, String datePattern) throws IOException
    {
        // 改动只有这点:以线程名命名日志文件
        super(layout,
                "log" + File.separator + Thread.currentThread().getName(),
                datePattern);
    }
}

 

 封装获得线程独立日志的Logger实例的类:

package threadlogger;

import java.io.IOException;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import threadlogger.appender.ThreadSeperateDailyRollingFileAppender;

/**
 * @author Kevin Kwok
 */
public class ThreadLogger
{
    ThreadLogger() {};

    public static Logger getLogger()
    {
        Logger logger = null;
        // 创建一个Logger实例, 就以线程名命名
        logger = Logger.getLogger(Thread.currentThread().getName());
        
        PatternLayout layout = new PatternLayout("%-4r %-5p [%d{yyyy-MM-dd HH:mm:ss,SSS}] %l%t: %m%n");

        // 控制台输出
        ConsoleAppender concoleAppender = new ConsoleAppender(layout, "System.out");

        // 文件输出
        ThreadSeperateDailyRollingFileAppender R = null;
        try
        {
            R = new ThreadSeperateDailyRollingFileAppender(layout, "'.'yyyy-MM-dd'.log'");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        // 参数配置, 因为没有找到仅靠配置文件的办法, 只好放在这里设
        R.setAppend(false);
        R.setImmediateFlush(true);
        R.setThreshold(Level.WARN);

        // 绑定到Logger
        logger.setLevel(Level.DEBUG);
        logger.addAppender(concoleAppender);
        logger.addAppender(R);
        
        return logger;
    }

}

 测试例程:package testlog;

import org.apache.log4j.Logger;

import threadlogger.ThreadLogger;

/**
 * @author Kevin Kwok
 */
public class TestLog
{
    // 这是主线程的Logger,这些不需独立日志的类也可以创建为普通的Logger,通过配置文件配置参数
    static Logger logger = ThreadLogger.getLogger();

    public TestLog() {}

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        logger.warn(TestLog.class + " started!");
        
        ThreadBody threadBody = new ThreadBody();
        for(int i=0; i<5; ++i) {
            new Thread(threadBody).start();
        }

        logger.debug("this is debug");
        logger.info("this is info");
        logger.warn("this is warn");
        logger.error("this is error");
    }

}

class ThreadBody implements Runnable
{
    public ThreadBody() {}

    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run()
    {
        // 注意线程独立的Logger实例要在run方法内实现
        Logger logger = ThreadLogger.getLogger();
        
        logger.warn(Thread.currentThread().getName() + " started!");
        
        logger.debug("this is debug");
        logger.info("this is info");
        logger.warn("this is warn");
        logger.error("this is error");

        logger.warn(Thread.currentThread().getName() + " finished!");
    }
    
}

 

测试结果:

 

0    WARN  [2012-11-05 14:31:40,227] testlog.TestLog.main(TestLog.java:21)main: class testlog.TestLog started!
27   DEBUG [2012-11-05 14:31:40,254] testlog.TestLog.main(TestLog.java:28)main: this is debug
27   INFO  [2012-11-05 14:31:40,254] testlog.TestLog.main(TestLog.java:29)main: this is info
27   WARN  [2012-11-05 14:31:40,254] testlog.TestLog.main(TestLog.java:30)main: this is warn
28   ERROR [2012-11-05 14:31:40,255] testlog.TestLog.main(TestLog.java:31)main: this is error
30   WARN  [2012-11-05 14:31:40,257] testlog.ThreadBody.run(TestLog.java:49)Thread-1: Thread-1 started!
33   WARN  [2012-11-05 14:31:40,260] testlog.ThreadBody.run(TestLog.java:49)Thread-0: Thread-0 started!
36   WARN  [2012-11-05 14:31:40,263] testlog.ThreadBody.run(TestLog.java:49)Thread-3: Thread-3 started!
38   WARN  [2012-11-05 14:31:40,265] testlog.ThreadBody.run(TestLog.java:49)Thread-2: Thread-2 started!
40   DEBUG [2012-11-05 14:31:40,267] testlog.ThreadBody.run(TestLog.java:51)Thread-2: this is debug
40   INFO  [2012-11-05 14:31:40,267] testlog.ThreadBody.run(TestLog.java:52)Thread-2: this is info
40   WARN  [2012-11-05 14:31:40,267] testlog.ThreadBody.run(TestLog.java:53)Thread-2: this is warn
41   ERROR [2012-11-05 14:31:40,268] testlog.ThreadBody.run(TestLog.java:54)Thread-2: this is error
41   WARN  [2012-11-05 14:31:40,268] testlog.ThreadBody.run(TestLog.java:56)Thread-2: Thread-2 finished!
44   DEBUG [2012-11-05 14:31:40,271] testlog.ThreadBody.run(TestLog.java:51)Thread-3: this is debug
46   INFO  [2012-11-05 14:31:40,273] testlog.ThreadBody.run(TestLog.java:52)Thread-3: this is info
46   WARN  [2012-11-05 14:31:40,273] testlog.ThreadBody.run(TestLog.java:53)Thread-3: this is warn
47   ERROR [2012-11-05 14:31:40,274] testlog.ThreadBody.run(TestLog.java:54)Thread-3: this is error
47   WARN  [2012-11-05 14:31:40,274] testlog.ThreadBody.run(TestLog.java:56)Thread-3: Thread-3 finished!
38   WARN  [2012-11-05 14:31:40,265] testlog.ThreadBody.run(TestLog.java:49)Thread-4: Thread-4 started!
49   DEBUG [2012-11-05 14:31:40,276] testlog.ThreadBody.run(TestLog.java:51)Thread-1: this is debug
50   INFO  [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:52)Thread-1: this is info
50   WARN  [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:53)Thread-1: this is warn
50   ERROR [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:54)Thread-1: this is error
50   WARN  [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:56)Thread-1: Thread-1 finished!
50   DEBUG [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:51)Thread-0: this is debug
50   INFO  [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:52)Thread-0: this is info
50   DEBUG [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:51)Thread-4: this is debug
50   WARN  [2012-11-05 14:31:40,277] testlog.ThreadBody.run(TestLog.java:53)Thread-0: this is warn
51   INFO  [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:52)Thread-4: this is info
51   ERROR [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:54)Thread-0: this is error
51   WARN  [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:53)Thread-4: this is warn
51   ERROR [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:54)Thread-4: this is error
51   WARN  [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:56)Thread-0: Thread-0 finished!
51   WARN  [2012-11-05 14:31:40,278] testlog.ThreadBody.run(TestLog.java:56)Thread-4: Thread-4 finished!

 

 同时,log文件夹下出现了main、Thread-0~Thread-4五个日志文件,记录了各自线程的信息。

 

 

参考:

log4j 动态日志文件名 的线程安全问题

- End -

1
3
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics