log4j flush

現在工作中遇到高頻寫日誌,如果寫一條日誌,log4j flush一次,那麼勢必對服務器的性能會產生一定影響,那麼現在想要實現1秒鐘 1分鐘flush 一次該怎麼辦?
log4j 只要繼承至 fileappender 則都可以immediateflush 屬性。
經實測當沒有指定該屬性時 默認爲true
那麼我們怎麼做到呢?
web項目繼承servlet設置一個定時任務來手動flush 具體參考如下代碼
Set<FileAppender> flushedFileAppenders = new HashSet<FileAppender>();
Enumeration currentLoggers = LogManager.getLoggerRepository().getCurrentLoggers();
    while(currentLoggers.hasMoreElements())
    {
        Object nextLogger = currentLoggers.nextElement();
        if(nextLogger instanceof Logger)
        {
             Logger currentLogger = (Logger) nextLogger;
             Enumeration allAppenders = currentLogger.getAllAppenders();
             while(allAppenders.hasMoreElements())
             {
                  Object nextElement = allAppenders.nextElement();
                  if(nextElement instanceof DailyRollingFileAppender)
                  {
                      DailyRollingFileAppender fileAppender = (DailyRollingFileAppender) nextElement;
                      System.out.println(fileAppender.getName());
                  if(!flushedFileAppenders.contains(fileAppender) && !fileAppender.getImmediateFlush())
                 {
                     flushedFileAppenders.add(fileAppender);
                     fileAppender.setImmediateFlush(true);
                     currentLogger.info("FLUSH");
                     fileAppender.setImmediateFlush(false);
                                    }
                   else{
                    }
               }
         }
    }
}
這裏源碼很好讀懂 就是從所有的容器中讀取出所有的logger 設置成true 之後再設置成flase。
但是這裏有一個關鍵點。
再設置爲true 需要再接着info 一下,只設置爲true 是不能觸發flush.只有再接着打條日誌。觸發下flush
這就是Log4j1 處理定時flush的一種方式了。 

現又發現另外一種方式 那就是自己寫個appender 如下
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提高性能,又想定時強制輸出以不影響某些依賴日誌輸出的後續流程的場景
 * 
 */
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>

這樣log4j1 的flush就完美解決了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章