自定义log4j日志文件命名规则
项目中的日志需要采用一致的命名规范和文件规范,命名规则为:项目模块标识_index_日期时间_日志级别.log,且每个级别日志文件放在单独的文件夹,且每个文件夹下日志的数量不得超过10个,当数量超过限制时,删除相对较旧的日志,保留较新的日志。
但是发现log4j并不能满足此要求,于是
根据log4j的API定义自己的FileAppender
代码如下:
package com.dear.simpler.dbrpc.util.log; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /**; * * @author lixiang * 自定义log文件的命名规则 */ public class MyLogFileAppender extends RollingFileAppender { private long nextRollover = 0; private static AtomicInteger logIndex = new AtomicInteger(0); //index public void rollOver() { File file = null; 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); if (maxBackupIndex > 0) { file = new File(getRollingFileName(fileName, logIndex.incrementAndGet())); if (fileExisted(file)){ file = new File(getRollingFileName(fileName, logIndex.incrementAndGet())); } deleteOldFile(file.getParentFile(), maxBackupIndex); this.closeFile(); } try { this.setFile(getRollingFileName(fileName, logIndex.get()), 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) { //使用正则表达式替代index Pattern p = Pattern.compile("_\\d+\\_"); Matcher m=p.matcher(fileName); String str = m.replaceFirst(String.format("_%d_", index)); SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); //日期 String dateString = format.format(new Date(System.currentTimeMillis())); str = str.replaceAll("\\d{14}", dateString); return str; } public synchronized void setFile(String fileName, boolean append, //修改文件名 boolean bufferedIO, int bufferSize) throws IOException { SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); //日期 String dateString = format.format(new Date(System.currentTimeMillis())); String temp = String.format(fileName , dateString); //文件名 super.setFile(temp, append, bufferedIO, bufferSize); if(append) { File f = new File(temp); ((CountingQuietWriter)this.qw).setCount(f.length()); } } private boolean fileExisted(File file){ boolean res = false; String[] fts = file.getName().split("_"); File parentFile = file.getParentFile(); for(File f : parentFile.listFiles()){ String[] fns = f.getName().split("_"); if(fns[0].equals(fts[0]) && fns[1].equals(fts[1])){ res = true; break; } } return res; } private void deleteOldFile(File dir , int maxInt){ if(getFileNum(dir) >= maxBackupIndex ){ File[] files = orderByDate(dir); for (int i = 0; i <= files.length - maxBackupIndex; i++) { File f = files[i]; f.delete(); } } } private int getFileNum(File file){ return file.list().length; } //将文件按日期排序 public File[] orderByDate(File dir) { File[] fs = dir.listFiles(); Arrays.sort(fs,new Comparator< File>(){ @Override public int compare(File f1, File f2) { long diff = f1.lastModified() - f2.lastModified(); if (diff > 0) return 1; else if (diff == 0) return 0; else return -1; } @Override public boolean equals(Object obj) { return true; } }); return fs; } @Override protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } }
对应的log4j.properties的配置文件如下
### set log levels ### log4j.rootLogger = out,E,I #log4j.logger.com.dear.simpler.dbrpc.util.log.TestUtil=out,D log4j.appender.D = com.dear.simpler.dbrpc.util.log.MyLogFileAppender log4j.appender.D.File = ../../logs/db_logs/debug/DB_0_%s_debug.log log4j.appender.D.Append = true log4j.appender.D.MaxFileSize=1024MB log4j.appender.D.MaxBackupIndex=10 log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout log4j.appender.D.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n log4j.appender.E = com.dear.simpler.dbrpc.util.log.MyLogFileAppender log4j.appender.E.File = ../../logs/db_logs/error/DB_0_%s_error.log log4j.appender.E.Append = true log4j.appender.E.MaxFileSize=10MB log4j.appender.E.MaxBackupIndex=10 log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout log4j.appender.E.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n log4j.appender.I = com.dear.simpler.dbrpc.util.log.MyLogFileAppender log4j.appender.I.File = ../../logs/db_logs/info/DB_0_%s_info.log log4j.appender.I.Append = true log4j.appender.I.MaxFileSize=10MB log4j.appender.I.MaxBackupIndex=10 log4j.appender.I.Threshold = INFO log4j.appender.I.layout = com.dear.simpler.dbrpc.util.log.ExPatternLayout log4j.appender.I.layout.ConversionPattern = [%d{yyyy/MM/dd HH:mm:ss,SSS}][%T:%t][%p][%F:%L:%M][%m]%n
输出的日志文件命名如下
log4j自定义生成文件的名称
我们在使用Log4j的RollingFileAppender循环生成文件的时候,生成的文件的名称有点儿恶心,例如,文件名称为app.log,那么生成的文件名依次为app.log.1,app.log.2,....
那么如何去改变生成文件的名称的规则呢?下面是一个简单示例:
log4j.properties
log4j.logger.major= INFO, majorMsg log4j.additivity.logError = false log4j.appender.majorMsg=com.zws.log.MyRollingFileAppender log4j.appender.majorMsg.File=${catalina.home}/logs/itc/majorMsg.log log4j.appender.majorMsg.layout=org.apache.log4j.PatternLayout log4j.appender.majorMsg.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss}|%p|%C|%M|%L|%m%n log4j.appender.majorMsg.MaxFileSize=1KB log4j.appender.majorMsg.MaxBackupIndex=10
MyRollingFileAppender.java
package com.zws.log; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; import org.apache.log4j.Priority; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /** * * @author wensh.zhu * */ public class MyRollingFileAppender extends RollingFileAppender { private long nextRollover = 0; public void rollOver() { File target; File file; if (qw != null) { long size = ((CountingQuietWriter) qw).getCount(); nextRollover = size + maxFileSize; } LogLog.debug("maxBackupIndex=" + maxBackupIndex); boolean renameSucceeded = true; if (maxBackupIndex > 0) { //删除序号最大(最早的文件)的文件 file = new File(genFileName(fileName, maxBackupIndex)); if (file.exists()) renameSucceeded = file.delete(); //所有文件名序号加1 for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) { file = new File(genFileName(fileName, i)); if (file.exists()) { target = new File(genFileName(fileName, i + 1)); renameSucceeded = file.renameTo(target); } } if (renameSucceeded) { target = new File(genFileName(fileName, 1)); this.closeFile(); file = new File(fileName); renameSucceeded = file.renameTo(target); 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 (renameSucceeded) { try { 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 genFileName(String name, int index) { String fileName = ""; if (index > 0) { String num = index < 10 ? "0" + index : String.valueOf(index); fileName = name.replace(".log", "") + "_" + num + ".log"; } else { fileName = name; } return fileName; } protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } }
以上示例将文件名的生成规则为:如果文件名为app.log,那么后续的文件为app_01.log,app_02.log.
仅为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家