Log4j的扩展-支持设置最大日志数量的DailyRollingFileAppender

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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
yout=org.apache.log4j.PatternLayout
yout.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
yout=org.apache.log4j.PatternLayout
yout.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()⽅法⾥⾯加上删除过多的⽇志就不⾏了吗,的确可以这么做:
1package org.apache.log4j;
2
3import org.slf4j.Logger;
4import org.slf4j.LoggerFactory;
5
6import java.io.File;
7import java.io.FileFilter;
8import java.io.IOException;
9import java.text.ParseException;
10import java.util.*;
11
12public class MyDailyRollingFileAppender extends DailyRollingFileAppender {
13private static Logger logger = LoggerFactory.getLogger(MyDailyRollingFileAppender.class);
14private int maxFileSize = 60;
15
16
17void rollOver() throws IOException {
18super.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*/
31private void deleteOvermuch(List<File> fileList) {
32if (fileList.size() > maxFileSize) {
33for (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*/
44private void sortFiles(List<File> fileList) {
45 Collections.sort(fileList, new Comparator<File>() {
46public int compare(File o1, File o2) {
47try {
48if (getDateStr(o1).isEmpty()) {
49return 1;
50 }
51 Date date1 = sdf.parse(getDateStr(o1));
52
53if (getDateStr(o2).isEmpty()) {
54return -1;
55 }
56 Date date2 = sdf.parse(getDateStr(o2));
57
58if (date1.getTime() > date2.getTime()) {
59return 1;
60 } else if (date1.getTime() < date2.getTime()) {
61return -1;
62 }
63 } catch (ParseException e) {
64 logger.error("", e);
65 }
66return 0;
67 }
68 });
69 }
70
71private String getDateStr(File file) {
72if (file == null) {
73return "null";
74 }
75return file.getName().replaceAll(new File(fileName).getName(), "");
76 }
77
78/**
79 * 获取所有⽇志⽂件,只有⽂件名符合DatePattern格式的才为⽇志⽂件
80 * @return
81*/
82private List<File> getAllLogs() {
83final File file = new File(fileName);
84 File logPath = file.getParentFile();
85if (logPath == null) {
86 logPath = new File(".");
87 }
88
89 File files[] = logPath.listFiles(new FileFilter() {
90public boolean accept(File pathname) {
91try {
92if (getDateStr(pathname).isEmpty()) {
93return true;
94 }
95 sdf.parse(getDateStr(pathname));
96return true;
97 } catch (ParseException e) {
98 logger.error("", e);
99return false;
100 }
101 }
102 });
103return Arrays.asList(files);
104 }
105public int getMaxFileSize() {
106return maxFileSize;
107 }
108
109public void setMaxFileSize(int maxFileSize) {
110this.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
yout=org.apache.log4j.PatternLayout
yout.ConversionPattern= [%d{yyyy-MM-dd HH\:mm\:ss}]%-5p %c(line\:%L) %x-%m%n
其实Log4j⽀持这种通⽤的配置⽅法,注意上⾯配置第四⾏,不⽤另外添加其他任何代码。

相关文档
最新文档