package test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

/**
 * 既能设置buffer大小,也能定时刷新(无论是否达到设定的buffer大小)的appender;适用于既想使用buffer的IO提高性能,又想定时强制输出以不影响某些依赖日志输出的后续流程的场景
 * 
 * @author pf-miles
 * @since 2015-4-7
 */
public class TimedBufferedDailyRollingFileAppender extends DailyRollingFileAppender {

    private static final int                                         CHECK_INTERVAL      = 5;
    private static final Object                                      appendersLock       = new Object();
    private static final List<TimedBufferedDailyRollingFileAppender> appenders           = new ArrayList<TimedBufferedDailyRollingFileAppender>();
    static {
        new Thread(new Runnable() {

            public void run() {
                while (true) {
                    try {
                        synchronized (appendersLock) {
                            for (TimedBufferedDailyRollingFileAppender appender : appenders)
                                appender.flush();
                        }
                        Thread.sleep(CHECK_INTERVAL * 1000);
                    } catch (Throwable t) {
                        // ignore...
                    }
                }
            }
        }, "TimedBufferedDailyRollingFileAppender-timed-flush").start();
    }
    private static final int                                         DEFAULT_BUFFER_SIZE = 1024 * 1024;                                           // 默认1MB的buffer

    protected int                                                    flushInterval       = 60;                                                    // 默认的定时刷新间隔(秒)

    private Date                                                     flushTime           = new Date();                                            // 下一次刷新的时间点

    public TimedBufferedDailyRollingFileAppender(){
        super();
        this.setBufferedIO(true);
        this.setBufferSize(DEFAULT_BUFFER_SIZE);// 默认1MB的buffer
        this.setImmediateFlush(false);
        synchronized (appendersLock) {
            appenders.add(this);
        }
    }

    public TimedBufferedDailyRollingFileAppender(Layout layout, String filename, String datePattern) throws IOException{
        super(layout, filename, datePattern);
        this.setBufferedIO(true);
        this.setBufferSize(DEFAULT_BUFFER_SIZE);// 默认1MB的buffer
        this.setImmediateFlush(false);
        synchronized (appendersLock) {
            appenders.add(this);
        }
    }

    private void flush() {
        if (!(new Date()).after(flushTime)) return;
        if (!checkEntryConditions()) return;
        qw.flush();
        this.flushTime = new Date(System.currentTimeMillis() + this.flushInterval * 1000);
    }

    public void setFlushInterval(int flushInterval) {
        if (flushInterval < CHECK_INTERVAL) flushInterval = CHECK_INTERVAL;// 至少CHECK_INTERVAL秒
        this.flushInterval = flushInterval;
    }

    // 本appender必须是bufferedIO, 否则没意义
    @Override
    public boolean getBufferedIO() {
        return true;
    }

    @Override
    public void setBufferedIO(boolean bufferedIO) {
        super.setBufferedIO(true);
    }

    @Override
    public void setImmediateFlush(boolean value) {
        super.setImmediateFlush(false);
    }

    @Override
    public boolean getImmediateFlush() {
        return false;
    }
}

配置使用样例:

<appender name="xxx" class="test.TimedBufferedDailyRollingFileAppender">
        <param name="file" value="/tmp/xxx.log"/>
        <param name="datePattern" value="'.'yyyy-MM-dd-HH"/>
        <param name="append" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <param name="flushInterval" value="10"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}|%p|%X{hostIp}||%m%n"/>
        </layout>
</appender>

pf_miles
483 声望10 粉丝

硬派程序员,反对假大空;