log4j自定义生成log日志文件名实例教程

发布时间:2020-04-12编辑:脚本学堂
有关log4j自定义生成log日志文件名的方法,将log4j输出的日志文件名实现自由定义,需要的朋友参考下。

在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文件名的时候,比如:
 

test_[process_name]_0_20111031.log
test_[process_name]_1_20111031.log
test_[process_name]_2_20111031.log
......

要在文件名显示是哪一个进程名,第一个文件为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

缺点:
配置文件必须要按自定义的格式来写,即log4j.appender.file.File=test-%s_%s_0.%s.log不能搞错了
RollingFileAppender的几个方法扩展的都不好,还把原来的代码copy过来修改的。