自定義log4j日志文件命名規則說明
自定義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.
僅為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet
推薦閱讀:
- log4j如何根據變量動態生成文件名
- log4j配置失效日志中打印Debug信息問題
- 淺談log4j的rootLogger及其他坑爹的地方
- Log4j.properties配置及其使用
- 關於log4j日志擴展—自定義PatternLayout