轮换文件
log4j可以按大小轮换文件(FileAppender, fileSize), 按天轮换文件 (DailyRollingFileAppender )
在我的某个应用场景中,使用log4j做数据落地,就是把每条日志数据格式化后,写入本地日志文件。
然后通过一个进程来读取所有轮换后的文件,分析每一条数据,入库(mongodb)。
做了如下的修改
1、除了使用文件大小来做轮换规则外,添加一个rollTime属性,表示需要轮换的时间s。
如果文件一直为0,不轮换,创建文件时记录下时间戳,定时与当前时间比较,超过rollTime,强制轮换。
2、同时修改轮换文件名称规则,默认的是.1,.2...这种形式。修改为.时间戳的形式。
其实还自定义了一个简单的Layout序列化数据。这个不是必须的。
使用方法,在log4j.xml中,
<appender
class="xxx.log.TimeRollingFileAppender"
name="ROLLING_FILE">
<param name="MaxBackupIndex" value="1024" />
<param name="Encoding" value="UTF-8" />
<param name="File" value="esb.log" />
<!--
<param name="BufferSize" value="8192" />
<param name="BufferedIO" value="true" />
-->
<param name="ImmediateFlush" value="true" />
<param name="RollTime" value="60" />
<param name="MaxFileSize" value="100MB" />
......
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Writer;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.FileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.LoggingEvent;
/**
* TODO 根据时间和大小轮换文件
*
* @author kimmking (mailto:qinjw@primeton.com)
*/
public class TimeRollingFileAppender extends FileAppender {
/**
* The default maximum file size is 10MB.
*/
protected long maxFileSize = 10 * 1024 * 1024;
/**
* There is one backup file by default.
*/
protected int maxBackupIndex = 1;
private long nextRollover = 0;
protected int rollTime = 60; // seconds
long fileTimeStamp = 0;
Timer timer = null;
private TimerTask getTask() {
return new TimerTask() {
@Override
public void run() {
// 时间戳
long result = System.currentTimeMillis() - fileTimeStamp - getRollTime() * 1000;
if (result > 0)
if (new File(fileName).length() > 0)
rollOver();
}
};
}
/**
* The default constructor simply calls its
* {@link FileAppender#FileAppender parents constructor}.
*/
public TimeRollingFileAppender() {
super();
timer = new Timer("TimeRollingFileAppender", true);
long period = rollTime * 1000;
TimerTask task = getTask();
timer.schedule(task, period, 1l); // 从一个轮换时间间隔以后,每秒检查一次
}
/**
* Returns the value of the <b>MaxBackupIndex</b> option.
*/
public int getMaxBackupIndex() {
return maxBackupIndex;
}
/**
* Get the maximum size that the output file is allowed to reach before
* being rolled over to backup files.
*
* @since 1.1
*/
public long getMaximumFileSize() {
return maxFileSize;
}
/**
* Implements the usual roll over behaviour.
*
* <p>
* If <code>MaxBackupIndex</code> is positive, then files {
* <code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code> are
* renamed to {<code>File.2</code>, ...,
* <code>File.MaxBackupIndex</code> . Moreover, <code>File</code> is
* renamed <code>File.1</code> and closed. A new <code>File</code> is
* created to receive further log output.
*
* <p>
* If <code>MaxBackupIndex</code> is equal to zero, then the
* <code>File</code> is truncated with no backup files created.
*/
public// synchronization not necessary since doAppend is alreasy synched
synchronized void rollOver() {
File target;
File file;
if (qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
LogLog.debug("rolling over count=" + size);
// if operation fails, do not roll again until
// maxFileSize more bytes are written
nextRollover = size + maxFileSize;
}
// LogLog.debug("maxBackupIndex=" + maxBackupIndex);
long timestamp = System.currentTimeMillis();
boolean renameSucceeded = true;
// If maxBackups <= 0, then there is no file renaming to be done.
// if (maxBackupIndex > 0) {
// // Delete the oldest file, to keep Windows happy.
// file = new File(fileName + '.' + maxBackupIndex);
// if (file.exists())
// renameSucceeded = file.delete();
// // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3,
// // 2}
// for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
// file = new File(fileName + "." + i);
// if (file.exists()) {
// target = new File(fileName + '.' + (i + 1));
// LogLog.debug("Renaming file " + file + " to " + target);
// renameSucceeded = file.renameTo(target);
// }
// }
//
// if (renameSucceeded) {
// Rename fileName to fileName.1
target = new File(fileName + "." + timestamp);
this.closeFile(); // keep windows happy.
file = new File(fileName);
LogLog.debug("Renaming file " + file + " to " + target);
renameSucceeded = file.renameTo(target);
//
// if file rename failed, reopen file with append = true
//
if (!renameSucceeded) {
try {
this.setFile(fileName, true, bufferedIO, bufferSize);
} catch (IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile(" + fileName + ", true) call failed.", e);
}
}
// }
// }
//
// if all renames were successful, then
//
if (renameSucceeded) {
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(fileName, false, bufferedIO, bufferSize);
nextRollover = 0;
} catch (IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile(" + fileName + ", false) call failed.", e);
}
}
}
public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException {
File file = new File(fileName).getParentFile();
if (!file.exists())
file.mkdirs();
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
if (append) {
File f = new File(fileName);
((CountingQuietWriter) qw).setCount(f.length());
}
fileTimeStamp = System.currentTimeMillis();
}
public void setRollTime(int rollTime) {
if (this.rollTime == rollTime)
return;
this.rollTime = rollTime;
// if (this.timer != null) {
// this.timer.cancel();
// }
// this.timer = new Timer("TimeRollingFileAppender", true);
//
// if (rollTime > 0) {
// long period = rollTime * 1000;
// this.timer.schedule(getTask(), period, period);
// }
}
public final int getRollTime() {
return this.rollTime;
}
/**
* Set the maximum number of backup files to keep around.
*
* <p>
* The <b>MaxBackupIndex</b> option determines how many backup files are
* kept before the oldest is erased. This option takes a positive integer
* value. If set to zero, then there will be no backup files and the log
* file will be truncated when it reaches <code>MaxFileSize</code>.
*/
public void setMaxBackupIndex(int maxBackups) {
this.maxBackupIndex = maxBackups;
}
/**
* Set the maximum size that the output file is allowed to reach before
* being rolled over to backup files.
*
* <p>
* This method is equivalent to {@link #setMaxFileSize} except that it is
* required for differentiating the setter taking a <code>long</code>
* argument from the setter taking a <code>String</code> argument by the
* JavaBeans {@link java.beans.Introspector Introspector}.
*
* @see #setMaxFileSize(String)
*/
public void setMaximumFileSize(long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
* Set the maximum size that the output file is allowed to reach before
* being rolled over to backup files.
*
* <p>
* In configuration files, the <b>MaxFileSize</b> option takes an long
* integer in the range 0 - 2^63. You can specify the value with the
* suffixes "KB", "MB" or "GB" so that the integer is interpreted being
* expressed respectively in kilobytes, megabytes or gigabytes. For example,
* the value "10KB" will be interpreted as 10240.
*/
public void setMaxFileSize(String value) {
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
}
protected void setQWForFiles(Writer writer) {
this.qw = new CountingQuietWriter(writer, errorHandler);
}
/**
* This method differentiates RollingFileAppender from its super class.
*
* @since 0.9.0
*/
protected void subAppend(LoggingEvent event) {
super.subAppend(event);
if (fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}
}
转载地址:http://www.iteye.com/topic/1006379