文档章节

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

Zero零_度
 Zero零_度
发布于 2017/07/24 19:55
字数 1309
阅读 11
收藏 0

Log4j现在已经被大家熟知了,所有细节都可以在网上查到,Log4j支持Appender,其中DailyRollingFileAppender是被经常用到的Appender之一。在讨论今天的主题之前,我们先看下另外一个Appender。

最常用的Appender——RollingFileAppender

下面是RollingFileAppender的一个Log4j配置样例(配置1):

按 Ctrl+C 复制代码

 

按 Ctrl+C 复制代码

RollingFileAppender使用MaxFileSize设置一个日志文件的最大大小,当产生多个日志时,会在日志名称后面加上".1"、".2"、……这样的后缀,我们可以看到RollingFileAppender有个属性MaxBackupIndex,这个属性通过限制日志文件名后缀".n"中的n大小来限制日志数量,比如上面MaxBackupIndex=10,其实最大日志数量为11。我们知道这个有这个限制是很必要的,当我们的程序在服务器上运行时,随着时间的迁移,日志会越来越多,如果对日志数量没有限制,日志大小会越来越大,最后甚至占满整个硬盘。

可以按照周期时间来滚动日志文件的Appender——DailyRollingFileAppender

下面是DailyRollingFileAppender的一个Log4j配置样例(配置2):

按 Ctrl+C 复制代码

 

按 Ctrl+C 复制代码

 

DailyRollingFileAppender特点是固定周期时间生成一个日志文件,比如,默认情况是每天生成一个文件。这种日志可以方便根据时间来定位日志位置,使日志清晰易查。但是这种日志有个不好地方是,不能限制日志数量,MaxBackupIndex属性和MaxFileSize在DailyRollingFileAppender中是无效的,我们上面已经提到限制日志数量的必要性。这里有两个解决办法:

  • linux上crontab+shell
  • java进程里面起一个线程,定期扫描日志文件夹。

但是这两种方法都不是很方便,有没有更好的办法呢?

重写DailyRollingFileAppender——MyDailyRollingFileAppender

查看DailyRollingFileAppender源代码,发现rollOver()方法是用来生成文件的,当调用subAppend()方法时会根据判断当前时间是否大于应该生成新文件的时间了(具体实现可以查看源码,逻辑还是比较清晰的),如果大于,就生成。首先把当前日志重命名,命名格式为test.log.yyyy-MM-dd-HH-mm,然后重新建test.log文件。看到这里我们就可以想,在rollOver()方法里面加上删除过多的日志就不行了吗,的确可以这么做:

复制代码

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

复制代码

 

首先,要注意的就是怎么判断日志文件夹中的日志是否是日志还是另外不相关的文件,比如备份的日志、控制台日志等。我使用的方法就是判断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支持这种通用的配置方法,注意上面配置第四行,不用另外添加其他任何代码。

本文转载自:http://www.cnblogs.com/rembau/p/5201001.html

共有 人打赏支持
Zero零_度
粉丝 67
博文 1245
码字总数 252866
作品 0
程序员
spring boot(8)默认日志logback配置

1 日志简介 Spring Boot使用Commons Logging记录所有内部日志,但是它将底层日志实现打开,为Java.Util.Logging,Log4J2和Logback提供默认配置。 在每个案例中,loggers都预先配置,以使用控...

刘胜球
2017/10/31
0
0
log4j.properties配置与加载应用

log4j.properties总结: 一、介绍 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、U...

Sobey
2015/01/08
0
0
Java Log4J 使用教程(java日志)

简介 2. 安装 3. log4j基本概念 3.1. Logger 3.2. Appender 3.2.1. 使用ConsoleAppender 3.2.2. 使用FileAppender 3.2.3. 使用WriterAppender 3.3. Layout 3.4. 基本示例 3.4.1. SimpleLayou......

lgxheartlikesea
2014/02/13
0
0
commons-logging和log4j

一、日志系统介绍 日志的重要性是随着系统的膨胀而显现的,在一个庞大的系统中查错没有各种日志信息是寸步难行的。所以在系统加入日志是必须的。 最原始的日志方式,就是在程序的适当地方添加...

hulubo
2011/12/25
0
0
logback与Log4J的区别

Logback和log4j是非常相似的,如果你对log4j很熟悉,那对logback很快就会得心应手。下面列了logback相对于log4j的一些优点: 更快的实现 Logback的内核重写了,在一些关键执行路径上性能提升...

凯文加内特
2015/05/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python3.6 取余运算

python中取余运算逻辑如下: 如果a 与d 是整数,d 非零,那么余数 r 满足这样的关系: a = qd + r , q 为整数,且0 ≤ |r| < |d|。 经过测试可发现,python3.6中取余运算得到的 r 是正整数;...

colinux
15分钟前
1
0
[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
3
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
3
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
1
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部