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

Log4j現在已經被大家熟知了,所有細節都可以在網上查到,Log4j支持Appender,其中DailyRollingFileAppender是被經常用到的Appender之一。在討論今天的主題之前,我們先看下另外一個Appender。

最常用的Appender——RollingFileAppender

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

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。我們知道這個有這個限制是很必要的,當我們的程序在服務器上運行時,隨著時間的遷移,日志會越來越多,如果對日志數量沒有限制,日志大小會越來越大,最后甚至占滿整個硬盤。

可以按照周期時間來滾動日志文件的Appender——DailyRollingFileAppender

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

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進程里面起一個線程,定期掃描日志文件夾。

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

重寫DailyRollingFileAppender——MyDailyRollingFileAppender

查看DailyRollingFileAppender源代碼,發現rollOver()方法是用來生成文件的,當調用subAppend()方法時會根據判斷當前時間是否大于應該生成新文件的時間了(具體實現可以查看源碼,邏輯還是比較清晰的),如果大于,就生成。首先把當前日志重命名,命名格式為test.log.yyyy-MM-dd-HH-mm,然后重新建test.log文件。看到這里我們就可以想,在rollOver()方法里面加上刪除過多的日志就不行了嗎,的確可以這么做:

?

  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個文件的情況下,刪除多余的日志文件。

然后,我們注意到我們上面的邏輯中用了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支持這種通用的配置方法,注意上面配置第四行,不用另外添加其他任何代碼。

?

轉載于:https://www.cnblogs.com/rembau/p/5201001.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257687.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257687.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257687.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VirtualBox虛擬機安裝CentOS 7

新建虛擬機 因為比較簡單&#xff0c;所以對于VirtualBox就不做過多介紹了&#xff0c;直接下載安裝即可&#xff0c;安裝好之后打開Oracle VM VirtualBox管理器&#xff0c;點擊新建&#xff0c;選擇Red Hat&#xff08;根據windows主機選擇 32/64 bit&#xff0c;通常會自動識…

mysql 指定賬戶已存在_安裝mysql時告訴我指定的賬戶已存在?

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云數據庫專家保駕護航&#xff0c;為用戶…

C語言:用字符讀取流和輸出流來讀寫入數據。(文本文件)

/* 文件的幾種操作模式: r:只讀 w:只寫 rw:可讀可寫 文件的分類&#xff1a; t:文本文件(字符文件) b:二進制文件(字節文件)注意&#xff1a; 采用只讀方式打開文件時,如果源文件不存在,打開文件會失敗&#xff01; 采用只寫方式打開文件時,不管源文件存不存在,都不會失敗…

PC 上訪問設備數據庫的方法

通過 .NET 訪問 .sdf 的數據庫的方法&#xff1a; 在 VS2005 IDE 中&#xff0c;創建 SQL MOible 數據庫&#xff0c;編輯表結果和填充數據。 具體是在 Server Explorer 中&#xff0c;右鍵單擊 “Data Connections”&#xff0c;選擇 “Add Connection”&#xff0c;新建一個 …

模板原理和操作數據類的觀點【艱難的一天,慢慢的會過去的】

1.模板原理&#xff1a;視圖類【將數據輸出到模板中&#xff0c;實現對視圖的控制】 smarty的類實現對視圖的控制【展示和smarty的基本語法&#xff1a;smarty需要它的庫進行支持】 面向對象的編程中對象的訪問和類的訪問本質上還是代碼空間的訪問&#xff0c;區別也在于對象的…

mysql 用戶 類別_從mysql里讀取用戶類型

##1、后端1(從mysql里讀取用戶類型)&#xff1a;from django import formsfrom django.forms import widgetsfrom django.forms import fieldsfrom app01 import modelsfrom django.forms import ModelChoiceField,ModelMultipleChoiceFieldfrom django.shortcuts import rende…

從C語言到C++成長經歷所得的一些技巧和感悟

我介紹幾個辦法&#xff0c;學習辦法&#xff0c;期望你能找到愛好1。必定要和喜愛編程的&#xff0c;或編程兇猛的&#xff0c;或常常編程的人&#xff0c;在一同&#xff0c;常常探討問題&#xff01;初學編程會有許多問題呈現&#xff0c;你自己很 難處理 c是我們必定要學的…

老子《道德經》第三十三章

上德不德&#xff0c;是以有德&#xff1b;下德不失德&#xff0c;是以無德。 上德無為而無不為&#xff0c;下德為之而有以為&#xff0c;上仁為之而無以為&#xff0c;上義為之而有以為。 上禮為之而莫之應&#xff0c;則攘臂而扔之。 故失道而后德&#xff0c;失德而后仁&am…

[Spring]-各種標注-零配置

個人學習筆記&#xff0c;記錄了一些比較基礎的標注&#xff1b; 1、controller 控制器&#xff08;注入服務&#xff09;2、service 服務&#xff08;注入dao&#xff09;3、repository dao&#xff08;實現dao訪問&#xff09;4、component pojo實例化到spring容器中&#xf…

mysql弄丟初始密碼_MySql密碼丟失

windows下mysql密碼忘記了第一步&#xff1a;netstat -nat(可以查看mysql是否啟動了&#xff0c;如果啟動了&#xff0c;可以用輸入net stop mysql(或者通過任務管理器結束進程))第二步&#xff1a;mysqld --skip-grant-tables&#xff0c;不要關閉窗口第三步&#xff1a;開啟一…

CodeForces-500C

傳送門 給n本不同重量的一摞書編號1&#xff5e;n。給定m次操作。操作b代表花費標號為b的書上方其他書的重量總和&#xff0c;將書b位移到這疊書的最上方。問初始書應該如何疊放&#xff0c;才能使m次操作后總花費最小 輸入 n本書 m次操作 n個數 書的重量 m個數 操作對象 輸出 …

java基礎篇---網絡編程(UDP程序設計)

UDP程序設計 在TCP的索引操作都必須建立可靠地連接&#xff0c;這樣一來肯定會浪費大量的系統性能&#xff0c;為了減少這種開銷&#xff0c;在網絡中又提供了另外一種傳輸協議---UDP,不可靠的連接&#xff0c;這種協議在各個聊天工具中被廣泛的應用。 咋UDP開發中使用Datagram…

bzoj - 2038: [2009國家集訓隊]小Z的襪子(hose)

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id2038 莫隊算法可以解決一類不修改、離線查詢問題。而這題可以用莫隊來做。 *我是看這個論文學會的&#xff1a;&#xff08;鏈接~&#xff09; 其實莫隊就是一種優化的暴力&#xff0c;只是把查詢都離線預先按照規則…

c++ 靜態變量賦值_Python變量及常量解釋說明

變量(1)在計算機程序中,變量不僅可以是數字,還可以是任意數據類型,變量子啊程序中就是一個變量名表示的,變量名必須是大小寫英文,數字,和"_"的組合,切不能以數字開頭.a 1 #變量a是一個整數1b "shuai" #變量b是一個字符串1c True #變量c是一個布爾值Tru…

Hibernate中session的clear(),flush(),evict()方法詳解

2019獨角獸企業重金招聘Python工程師標準>>> 一、Clear 方法 無論是Load 還是 Get 都會首先查找緩存&#xff08;一級緩存&#xff09; 如果沒有&#xff0c;才會去數據庫查找&#xff0c;調用Clear() 方法&#xff0c;可以強制清除Session緩存。例&#xff1a; pub…

快速排序和折半查找

package BinarySerach;import java.util.Scanner;public class BinarySerch {/***折半查找和快速排序*/static final int N 15;static void quickSort(int [] array,int left,int right){int f,t;int ltemp left;int rtemp right;//確定分界值f array[(leftright)/2];while(…

CANVAS運用-對圖片的壓縮上傳(僅針對移動瀏覽器)

最近在移動端設計頭像上傳功能時&#xff0c;原本是以<input type"file">直接通過formData上傳&#xff0c;然而實際使用情況是&#xff1a;對于過大的圖片&#xff08;高像素手機所拍攝的照片等&#xff09;上傳時間過長會導致上傳失敗&#xff0c;而每次都上…

mysql重命名數據表稱方式_在MySQL中,使用()重命名數據表。_學小易找答案

【單選題】( )的上海文壇被稱為“張愛玲年”。【多選題】下列哪些是屬于共集放大電路的特點?()【閱讀理解】Passage Two Thailand is to ban smoking on some of the country’s most popular tourist beaches, with the prospect of up to a year in prison for those caught…

40_自定義泛型方法及其應用

java的泛型不同于C的模板方法那么強大。java的泛型只停留在編譯階段&#xff0c;編譯通過后泛型特征被擦除&#xff0c;主要因為保證jvm的效率。 用泛型知識&#xff0c;寫一個交換數組元素的方法&#xff08;此方法只適合于引用類型數組!因為int[]不會自動轉為Integer[]!&…

SQL Server代理(11/12):維護計劃作業

SQL Server代理是所有實時數據庫的核心。代理有很多不明顯的用法&#xff0c;因此系統的知識&#xff0c;對于開發人員還是DBA都是有用的。這系列文章會通俗介紹它的很多用法。 在這一系列的上一篇&#xff0c;我們看了使用代理帳戶模仿Windows安全上下文完成作業步驟的工作。大…