Log4j的擴展-支持設置最大日誌數量的DailyRollingFileAppender

Log4j如今已經被你們熟知了,全部細節均可以在網上查到,Log4j支持Appender,其中DailyRollingFileAppender是被常常用到的Appender之一。在討論今天的主題以前,咱們先看下另一個Appender。java

最經常使用的Appender——RollingFileAppender

下面是RollingFileAppender的一個Log4j配置樣例(配置1):linux

log4j.appender.R=org.apache.log4j.RollingFileAppender  
log4j.appender.R.Threshold=DEBUG  
log4j.appender.R.File=test.log  
log4j.appender.R.layout=org.apache.log4j.PatternLayout  
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.R.MaxFileSize=20MB
log4j.appender.R.MaxBackupIndex=10

RollingFileAppender使用MaxFileSize設置一個日誌文件的最大大小,當產生多個日誌時,會在日誌名稱後面加上".1"、".2"、……這樣的後綴,咱們能夠看到RollingFileAppender有個屬性MaxBackupIndex,這個屬性經過限制日誌文件名後綴".n"中的n大小來限制日誌數量,好比上面MaxBackupIndex=10,其實最大日誌數量爲11。咱們知道這個有這個限制是很必要的,當咱們的程序在服務器上運行時,隨着時間的遷移,日誌會愈來愈多,若是對日誌數量沒有限制,日誌大小會愈來愈大,最後甚至佔滿整個硬盤。shell

能夠按照週期時間來滾動日誌文件的Appender——DailyRollingFileAppender

下面是DailyRollingFileAppender的一個Log4j配置樣例(配置2):apache

log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=test.log
log4j.appender.logfile.DataPattern='.'yyyy-MM-dd-HH-mm
log4j.appender.logfile.Threshold=debug
log4j.appender.logfile.encoding=UTF-8
log4j.appender.logfile.Append=false
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern= [%d{yyyy-MM-dd HH\:mm\:ss}]%-5p %c(line\:%L) %x-%m%n

 

DailyRollingFileAppender特色是固定週期時間生成一個日誌文件,好比,默認狀況是天天生成一個文件。這種日誌能夠方便根據時間來定位日誌位置,使日誌清晰易查。可是這種日誌有個很差地方是,不能限制日誌數量,MaxBackupIndex屬性和MaxFileSize在DailyRollingFileAppender中是無效的,咱們上面已經提到限制日誌數量的必要性。這裏有兩個解決辦法:服務器

  • linux上crontab+shell
  • java進程裏面起一個線程,按期掃描日誌文件夾。

可是這兩種方法都不是很方便,有沒有更好的辦法呢?app

重寫DailyRollingFileAppender——MyDailyRollingFileAppender

查看DailyRollingFileAppender源代碼,發現rollOver()方法是用來生成文件的,當調用subAppend()方法時會根據判斷當前時間是否大於應該生成新文件的時間了(具體實現能夠查看源碼,邏輯仍是比較清晰的),若是大於,就生成。首先把當前日誌重命名,命名格式爲test.log.yyyy-MM-dd-HH-mm,而後從新建test.log文件。看到這裏咱們就能夠想,在rollOver()方法裏面加上刪除過多的日誌就不行了嗎,的確能夠這麼作:this

 

  1 package org.apache.log4j;
  2 
  3 import org.slf4j.Logger;
  4 import org.slf4j.LoggerFactory;
  5 
  6 import java.io.File;
  7 import java.io.FileFilter;
  8 import java.io.IOException;
  9 import java.text.ParseException;
 10 import java.util.*;
 11 
 12 public class MyDailyRollingFileAppender extends DailyRollingFileAppender {
 13     private static Logger logger = LoggerFactory.getLogger(MyDailyRollingFileAppender.class);
 14     private int maxFileSize = 60;
 15 
 16 
 17     void rollOver() throws IOException {
 18         super.rollOver();
 19 
 20         logger.debug("保留文件數量" + maxFileSize + ",日誌文件名稱爲:" + fileName);
 21         List<File> fileList = getAllLogs();
 22         sortFiles(fileList);
 23         logger.debug(fileList.toString());
 24         deleteOvermuch(fileList);
 25     }
 26 
 27     /**
 28      * 刪除過多的文件
 29      * @param fileList 全部日誌文件
 30      */
 31     private void deleteOvermuch(List<File> fileList) {
 32         if (fileList.size() > maxFileSize) {
 33             for (int i = 0;i < fileList.size() - maxFileSize;i++) {
 34                 fileList.get(i).delete();
 35                 logger.debug("刪除日誌" + fileList.get(i));
 36             }
 37         }
 38     }
 39 
 40     /**
 41      * 根據文件名稱上的特定格式的時間排序日誌文件
 42      * @param fileList
 43      */
 44     private void sortFiles(List<File> fileList) {
 45         Collections.sort(fileList, new Comparator<File>() {
 46             public int compare(File o1, File o2) {
 47                 try {
 48                     if (getDateStr(o1).isEmpty()) {
 49                         return 1;
 50                     }
 51                     Date date1 = sdf.parse(getDateStr(o1));
 52 
 53                     if (getDateStr(o2).isEmpty()) {
 54                         return -1;
 55                     }
 56                     Date date2 = sdf.parse(getDateStr(o2));
 57 
 58                     if (date1.getTime() > date2.getTime()) {
 59                         return 1;
 60                     } else if (date1.getTime() < date2.getTime()) {
 61                         return -1;
 62                     }
 63                 } catch (ParseException e) {
 64                     logger.error("", e);
 65                 }
 66                 return 0;
 67             }
 68         });
 69     }
 70 
 71     private String getDateStr(File file) {
 72         if (file == null) {
 73             return "null";
 74         }
 75         return file.getName().replaceAll(new File(fileName).getName(), "");
 76     }
 77 
 78     /**
 79      *  獲取全部日誌文件,只有文件名符合DatePattern格式的才爲日誌文件
 80      * @return
 81      */
 82     private List<File> getAllLogs() {
 83         final File file = new File(fileName);
 84         File logPath = file.getParentFile();
 85         if (logPath == null) {
 86             logPath = new File(".");
 87         }
 88 
 89         File files[] = logPath.listFiles(new FileFilter() {
 90             public boolean accept(File pathname) {
 91                 try {
 92                     if (getDateStr(pathname).isEmpty()) {
 93                         return true;
 94                     }
 95                     sdf.parse(getDateStr(pathname));
 96                     return true;
 97                 } catch (ParseException e) {
 98                     logger.error("", e);
 99                     return false;
100                 }
101             }
102         });
103         return Arrays.asList(files);
104     }
105     public int getMaxFileSize() {
106         return maxFileSize;
107     }
108 
109     public void setMaxFileSize(int maxFileSize) {
110         this.maxFileSize = maxFileSize;
111     }
112 }

首先,要注意的就是怎麼判斷日誌文件夾中的日誌是不是日誌仍是另外不相關的文件,好比備份的日誌、控制檯日誌等。我使用的方法就是判斷sdf.parse(name.replaceAll(file.getName(), ""))是否報異常,若是不報異常就說明這個文件是日誌,固然不排除有的文件命名剛好符合這個格式,可是這樣的文件在日誌文件夾下,咱們認爲它就是一個日誌文件也是合理的。而後咱們根據sdf.parse(name.replaceAll(file.getName(), ""))解析出來的Date爲全部日誌進行升序排序放到一個隊列中,再保留這個隊列最後maxFileSize個文件的狀況下,刪除多餘的日誌文件。spa

而後,咱們注意到咱們上面的邏輯中用了maxFileSize這個變量,這個變量在MyDailyRollingFileAppender中,這個變量是怎麼賦值的呢?線程

log4j.appender.logfile=org.apache.log4j.MyDailyRollingFileAppender
log4j.appender.logfile.File=test.log
log4j.appender.logfile.DatePattern='.'yyyy-MM-dd-HH-m
log4j.appender.logfile.MaxFileSize=5
log4j.appender.logfile.Append=false
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern= [%d{yyyy-MM-dd HH\:mm\:ss}]%-5p %c(line\:%L) %x-%m%n

其實Log4j支持這種通用的配置方法,注意上面配置第四行,不用另外添加其餘任何代碼。debug

相關文章
相關標籤/搜索