log4j生成的日誌同時按大小和日期生成檔案,並自動清除過期日誌
最近做的專案,遇到了的情境:
1、要每個日誌按固定大小生成,超過設定大大小就生成新的日誌檔案
2、同時在檔名字後面加上日期,並自動按照設定的保留天數保留日誌,過期的日誌自動刪除。
3、設定同一日期最多生成日誌數,超過這個數量,則刪除今天最老的日誌,滾動排序,新生成的日誌永遠編號最大。
然而,log4j自帶的生成日誌的幾個方法,可以按照日期時間生成日誌,也可以按照設定的大小滾動生成日誌,就是沒有即按照大小生成,又在日誌名字後面加上日期,同時又清除過期日誌的方法。看了原始碼,決定綜合重新寫一個類,實現這些需求。
第一,準備jar :log4j-1.2.17.jar,commons-logging-1.1.1.jar,這2個就可以了,其他關於日誌的jar包就不要加進來了,在優先順序上會有衝突。
第二,定義一個類,繼承RollingFileAppender類,這個類是按照日誌大小滾動生成日誌,並把日誌編號。我就在這個類基礎上重新寫了其中的一些方法,加上日期和刪除功能,稍加改動就行了。
package log; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; public class RoolingAndDateFileAppender extends RollingFileAppender{ private String datePattern; private String dateStr="";//檔案後面的日期 private String expirDays="1";//保留最近幾天 private String isCleanLog="true"; private String maxIndex="100"; private File rootDir; public void setDatePattern(String datePattern){ if(null!=datePattern&&!"".equals(datePattern)){ this.datePattern=datePattern; } } public String getDatePattern(){ return this.datePattern; } public void rollOver(){ dateStr=new SimpleDateFormat(this.datePattern).format(new Date(System.currentTimeMillis())); File target = null; File file=null; if(qw!=null){ long size=((CountingQuietWriter)this.qw).getCount(); LogLog.debug("rolling over count="+size); } LogLog.debug("maxBackupIndex="+this.maxBackupIndex); //如果maxIndex<=0則不需命名 if(maxIndex!=null&&Integer.parseInt(maxIndex)>0){ //刪除舊檔案 file=new File(this.fileName+'.'+dateStr+'.'+Integer.parseInt(this.maxIndex)); if(file.exists()){ //如果當天日誌達到最大設定數量,則刪除當天第一個日誌,其他日誌為尾號減一 Boolean boo = reLogNum(); if(!boo){ LogLog.debug("日誌滾動重新命名失敗!"); } } } //獲取當天日期檔案個數 int count=cleanLog(); //生成新檔案 target=new File(fileName+"."+dateStr+"."+(count+1)); this.closeFile(); file=new File(fileName); LogLog.debug("Renaming file"+file+"to"+target); file.renameTo(target); try{ setFile(this.fileName,false,this.bufferedIO,this.bufferSize); }catch(IOException e){ LogLog.error("setFile("+this.fileName+",false)call failed.",e); } } public int cleanLog(){ int count=0;//記錄當天檔案個數 if(Boolean.parseBoolean(isCleanLog)){ File f=new File(fileName); rootDir=f.getParentFile(); File[] listFiles = rootDir.listFiles(); for(File file:listFiles){ if(file.getName().contains(dateStr)){ count=count+1;//是當天日誌,則+1 }else{ if(Boolean.parseBoolean(isCleanLog)){ //清除過期日誌 String[] split=file.getName().split("\\\\")[0].split("\\."); //校驗日誌名字,並取出日期,判斷過期時間 if(split.length==4 && isExpTime(split[2])){ file.delete(); } } } } } return count; } public Boolean isExpTime(String time){ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); try{ Date logTime=format.parse(time); Date nowTime=format.parse(format.format(new Date())); //算出日誌與當前日期相差幾天 int days=(int)(nowTime.getTime()-logTime.getTime())/(1000*3600*24); if(Math.abs(days)>=Integer.parseInt(expirDays)){ return true; }else{ return false; } }catch(Exception e){ LogLog.error(e.toString()); return false; } } /** * 如果當天日誌達到最大設定數量,則每次刪除尾號為1的日誌, * 其他日誌編號依次減去1,重新命名 * @return */ public Boolean reLogNum(){ boolean renameTo=false; File startFile = new File(this.fileName+'.'+dateStr+'.'+"1"); if(startFile.exists()&&startFile.delete()){ for(int i=2;i<=Integer.parseInt(maxIndex);i++){ File target = new File(this.fileName+'.'+dateStr+'.'+(i-1)); this.closeFile(); File file = new File(this.fileName+'.'+dateStr+'.'+i); renameTo=file.renameTo(target); } } return renameTo; } public String getDateStr() { return dateStr; } public void setDateStr(String dateStr) { this.dateStr = dateStr; } public String getExpirDays() { return expirDays; } public void setExpirDays(String expirDays) { this.expirDays = expirDays; } public String getIsCleanLog() { return isCleanLog; } public void setIsCleanLog(String isCleanLog) { this.isCleanLog = isCleanLog; } public String getMaxIndex() { return maxIndex; } public void setMaxIndex(String maxIndex) { this.maxIndex = maxIndex; } }
第三,log4j.properties檔案配置
log4j.rootLogger=ALL,R,CONSOLE log4j.appender.R=log.RoolingAndDateFileAppender #log4j.appender.R.Encoding=UTF-8 log4j.appender.R.file=../log/logs/logRecoed.log log4j.appender.R.Append=true log4j.appender.R.DatePattern=yyyy-MM-dd log4j.appender.R.MaxFileSize=5KB log4j.appender.R.maxIndex=10 log4j.appender.R.expirDays=1 log4j.appender.R.isCleanLog=true log4j.appender.R.layout.ConversionPattern=[%p] %t %c %d{yyyy-MM-dd HH:mm:ss} %m %n log4j.appender.R.layout=org.apache.log4j.PatternLayout #console log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout.ConversionPattern=[%p] %t %c %d{yyyy-MM-dd HH:mm:ss} %m %n log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
第四、測試:
public class TextLog {
public static void main(String[] args) {
Log log = LogFactory.getLog(TextLog.class);
for(int i=0;i<=500;i++){
System.out.println("迴圈"+"--"+i);
try{
System.out.println(1%0);
}catch(Exception e){
log.info("測試日誌"+"--"+"異常資訊"+i+":"+e);
}
}
}
}
第五,執行結果:
生成的日誌:
控制檯結果:
迴圈--0
[INFO] main log.TextLog 2018-01-11 23:00:11 測試日誌--異常資訊0:java.lang.ArithmeticException: / by zero
迴圈--1
[INFO] main log.TextLog 2018-01-11 23:00:11 測試日誌--異常資訊1:java.lang.ArithmeticException: / by zero
迴圈--2
[INFO] main log.TextLog 2018-01-11 23:00:11 測試日誌--異常資訊2:java.lang.ArithmeticException: / by zero
迴圈--3
。。。。。。
(完)