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; } }
配置使用样例:java
<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>