文档章节

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

Zero零_度
 Zero零_度
发布于 2017/03/09 09:49
字数 1333
阅读 81
收藏 0

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 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零_度
粉丝 69
博文 1268
码字总数 264512
作品 0
程序员
私信 提问
三方库--slf4j-log4j的使用

本文不去探究日志门面 slf4j 与其他众多日志框架 log4j、log4j2、logback、j.u.l(java.util.logging) 之间的关系,我们将重点关注 slf4j 与 log4j 的组合使用。 log4j 应该是最经典、使用人数...

_inkrain
04/28
0
0
从Log4j迁移到LogBack的理由

无论从设计上还是实现上,Logback相对log4j而言有了相对多的改进。不过尽管难以一一细数,这里还是列举部分理由为什么选择logback而不是log4j。牢记logback与log4j在概念上面是很相似的,它们...

Sub
2013/03/24
61.6K
48
log4j.properties配置与加载应用

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

Sobey
2015/01/08
19.7K
0
Log4j使用相对路径指定log文件及使用总结

Log4j在指定log文件位置时一般是使用绝对路径,这样在部署环境发生变化时显得十分麻烦,在网上找了很多种方法,个人感觉以下方法比较适用: 由于spring也会加载log4j.properties,如果加载不...

dodojava
2011/08/17
10.1K
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
436
0

没有更多内容

加载失败,请刷新页面

加载更多

PostgreSQL 11.3 locking

rudi
43分钟前
5
0
Mybatis Plus sql注入器

一、继承AbstractMethod /** * @author beth * @data 2019-10-23 20:39 */public class DeleteAllMethod extends AbstractMethod { @Override public MappedStatement injectMap......

一个yuanbeth
今天
8
1
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
今天
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
今天
8
0
队列-链式(c/c++实现)

队列是在线性表功能稍作修改形成的,在生活中排队是不能插队的吧,先排队先得到对待,慢来得排在最后面,这样来就形成了”先进先出“的队列。作用就是通过伟大的程序员来实现算法解决现实生活...

白客C
今天
78
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部