自定义log4j生成的log文件名

很多时候,log4j的RollingFileAppender配置如下:


log4j.logger.cn.lettoo.Test=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.File=test.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n


RollingFileAppender会自动在一个文件满了之后,生成一个如text.log.1的文件,一直生成到text.log.x(x值可配置log4j.appender.file.MaxBackupIndex=10)为止,再回写text.log。

当我们有需要在产生一些自定义的log文件名的时候,比如:
[quote]
test_[process_name]_0_20111031.log
test_[process_name]_1_20111031.log
test_[process_name]_2_20111031.log
......
[/quote]
要在文件名显示是哪一个进程名,第一个文件为0,后面是1,2,3......,并且要加上日期,再使用RollingFileAppender做简单的配置是无论如何也实现不了了。

打开RollingFileAppender.java的源码,我看到它主要是用setFile(),subAppend()和rollOver()这几个方法来实现具体的功能的:

public // synchronization not necessary since doAppend is alreasy synched
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);

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 + "." + 1);

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 {
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
if(append) {
File f = new File(fileName);
((CountingQuietWriter) qw).setCount(f.length());
}
}


/**
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();
}
}
}

如果我继承这个类,然后在子类里实现它的这三个方法,不就可以实现我要的功能了吗?
代码如下:


public class MWLogFileAppender extends RollingFileAppender {

private long nextRollover = 0;

public 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);

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);
file = new File(getRollingFileName(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);
file = new File(getRollingFileName(fileName, i));
if (file.exists()) {
//target = new File(fileName + '.' + (i + 1));
target = new File(getRollingFileName(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 + "." + 1);
target = new File(this.getRollingFileName(fileName, 1));

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);
}
}
}

private String getRollingFileName(String fileName, int index) {
Pattern p = Pattern.compile("_\\d+\\.");
Matcher m=p.matcher(fileName);

return m.replaceFirst(String.format("_%d.", index));
}

public synchronized void setFile(String fileName, boolean append,
boolean bufferedIO, int bufferSize) throws IOException {
String processName = "01";

SimpleDateFormat format = new SimpleDateFormat("MMddyyyy");
String dateString = format.format(new Date(System.currentTimeMillis()));

String processId = String.valueOf(Thread.currentThread().getId());
String temp = String.format(fileName, processName, dateString,
processId);
//System.out.println(temp);
super.setFile(temp, append, bufferedIO, bufferSize);
}

protected void subAppend(LoggingEvent event) {
super.subAppend(event);
if (fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}

}


在setFile方法里,通过String的替换来实现我要的自定义字符串的功能,当然,这里只是一个示例。
文件满了之后生成新的文件编号,不再在log后面加数据,而是在文件名体现,我这里加了一个getRollingFileName()来根据正则表达式来替换。

当然,配置文件可以修改如下了:

log4j.logger.cn.lettoo.Test=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.File=test-%s_%s_0.%s.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%d{MM/dd/yyyy HH:mm:ss.SSS} %m%n


虽然以上的做法满足了我的要求,但是我感觉也有缺点,主要是:
[list]
[*] 配置文件必须要按我自定义的格式来写,即log4j.appender.file.File=test-%s_%s_0.%s.log不能搞错了
[*] RollingFileAppender的几个方法扩展的都不好,还把原来的代码copy过来修改的。
[/list]

目前也没有想到更好的方法,暂时先记下来。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值