文档章节

logback系列之三:输出日志到文件(滚动)

小代码2016
 小代码2016
发布于 2016/03/25 11:37
字数 1041
阅读 350
收藏 0
点赞 1
评论 0
实际生产中,每天都有大量的日志生成,单个文件(FileAppender)已经不能满足要求,RollingFileAppender继承了FileAppender,并提供了更多的功能: 
  • 每天生成一个日志文件
  • 将前一天的日志重命名为包含日期的格式
  • 根据需要,删除过期历史日志

配置  

logback系列之二:输出日志到文件 类似,改动的地方: 

1. logback[-test].xml文件:  
Java代码   收藏代码
  1. <appender name="rollingAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">  
  2.     <file>/logs/heuristic.log</file>  
  3.     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
  4.         <fileNamePattern>/logs/heuristic-%d{yyyy-MM-dd}.log</fileNamePattern>  
  5.         <maxHistory>30</maxHistory>  
  6.     </rollingPolicy>  
  7.     <encoder><!-- 必须指定,否则不会往文件输出内容 -->  
  8.         <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>  
  9.     </encoder>  
  10.     <append>false</append>  
  11.     <prudent>false</prudent>  
  12. </appender>  
  13.   
  14. <root level="DEBUG">  
  15.     <appender-ref ref="rollingAppender" />  
  16. </root>  


调用测试类的方法,生成heuristic-2013-11-16.log文件。 


源码分析  

a. 如果指定了file属性,当天的文件名为file属性值(/logs/heuristic.log):  

ch.qos.logback.core.rolling.RollingFileAppender类  
Java代码   收藏代码
  1. public void start() {  
  2.     ...  
  3.     currentlyActiveFile = new File(getFile()); // 获取日志文件名  
  4. }  
  5.   
  6. public String getFile() {  
  7.     return rollingPolicy.getActiveFileName(); // 从滚动策略获取  
  8. }  


上面logback[-test].xml的rollingPolicy配置为 
ch.qos.logback.core.rolling.TimeBasedRollingPolicy类  

看下实现: 
Java代码   收藏代码
  1. public String getActiveFileName() {  
  2.   String parentsRawFileProperty = getParentsRawFileProperty();  
  3.   if (parentsRawFileProperty != null) { // logback.xml指定了file属性  
  4.     return parentsRawFileProperty; // 使用file值  
  5.   } else {  
  6.     return timeBasedFileNamingAndTriggeringPolicy  
  7.         .getCurrentPeriodsFileNameWithoutCompressionSuffix();  
  8.   }  
  9. }  
  10.   
  11. public String getParentsRawFileProperty() {  
  12.   return parent.rawFileProperty();  
  13. }  


ch.qos.logback.core.FileAppender类  
Java代码   收藏代码
  1. final public String rawFileProperty() {  
  2.   return fileName;  
  3. }  


b必须指定TriggeringPolicy<E>和RollingPolicy,否则不会打印日志:  

看下 
ch.qos.logback.core.rolling.RollingFileAppender类 : 
Java代码   收藏代码
  1. public void start() {  
  2.   if (triggeringPolicy == null) {  
  3.     addWarn("No TriggeringPolicy was set for the RollingFileAppender named "  
  4.         + getName());  
  5.     addWarn("For more information, please visit "+CODES_URL+"#rfa_no_tp");  
  6.     return;  
  7.   }  
  8.   
  9.   if (rollingPolicy == null) {  
  10.     addError("No RollingPolicy was set for the RollingFileAppender named "  
  11.         + getName());  
  12.     addError("For more information, please visit "+CODES_URL+"rfa_no_rp");  
  13.     return;  
  14.   }  

TimeBasedRollingPolicy类实现了上面的两个接口,triggeringPolicy和rollingPolicy都指向TimeBasedRollingPolicy的实例对象。 


c. 如果file指定,前一天的文件名改为fileNamePattern的值(/logs/heuristic-2013-11-15.log)。  

通过设置TimeBasedRollingPolicy的 maxHistory属性 ,可以控制已产生日志的数量。如果maxHistory设置为30,那么超过30天的log文件会被自动删除,这是通过RollingFileAppender的 rollover() 方法来实现的。 

该方法会调用 
ch.qos.logback.core.rolling.TimeBasedRollingPolicy类  
的rollover方法: 
Java代码   收藏代码
  1. public void rollover() throws RolloverFailure {  
  2.   // 当此方法调用时,假定前一天日志文件已经关闭  
  3.   String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy  
  4.       .getElapsedPeriodsFileName();  
  5.   
  6.   String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);  
  7.   
  8.   if (compressionMode == CompressionMode.NONE) {  
  9.     if (getParentsRawFileProperty() != null) {  
  10.       renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); // file指定,重命名为fileNamePattern格式。如果目标文件存在,则重命名失败  
  11.     } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }  
  12.   } else {  
  13.     if (getParentsRawFileProperty() == null) {  
  14.       future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem); // file未指定,异步压缩  
  15.     } else {  
  16.       future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem); // file指定,重命名并异步压缩  
  17.     }  
  18.   }  
  19.   
  20.   if (archiveRemover != null) {  
  21.     archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); // 删除历史日志  
  22.   }  
  23. }  


默认的archiveRemover为 ch.qos.logback.core.rolling.helper.DefaultArchiveRemover抽象类 : 
Java代码   收藏代码
  1. public void clean(Date now) {  
  2.   long nowInMillis = now.getTime();  
  3.   int periodsElapsed = computeElapsedPeriodsSinceLastClean(nowInMillis);  
  4.   lastHeartBeat = nowInMillis;  
  5.   if (periodsElapsed > 1) {  
  6.     addInfo("periodsElapsed = " + periodsElapsed);  
  7.   }  
  8.   // 从待删除日志的终止日期开始,每次回退一天,删除过期日志  
  9.   for (int i = 0; i < periodsElapsed; i++) {  
  10.     cleanByPeriodOffset(now, periodOffsetForDeletionTarget - i);  
  11.   }  
  12. }  
  13.   
  14. public void setMaxHistory(int maxHistory) {  
  15.   // 待删除日志的终止日期:回退(maxHistory+1)天  
  16.   this.periodOffsetForDeletionTarget = -maxHistory - 1;  
  17. }  


cleanByPeriodOffset为抽象方法,这里交由 
ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover子类 实现: 
Java代码   收藏代码
  1. protected void cleanByPeriodOffset(Date now, int periodOffset) {  
  2.   Date date2delete = rc.getRelativeDate(now, periodOffset); // 计算需要删除日志的日期  
  3.   String filename = fileNamePattern.convert(date2delete);  
  4.   File file2Delete = new File(filename);  
  5.   if (file2Delete.exists() && file2Delete.isFile()) {  
  6.     file2Delete.delete(); // 删除文件  
  7.     addInfo("deleting " + file2Delete);  
  8.     if (parentClean) {  
  9.       removeFolderIfEmpty(file2Delete.getParentFile());  
  10.     }  
  11.   }  
  12. }  


d. 如果要启用压缩,需要将fileNamePattern的后缀名设置为压缩格式,如:/logs/heuristic-%d{yyyy-MM-dd}.zip。  

看下 ch.qos.logback.core.rolling.RollingPolicyBase类 相关的代码: 
Java代码   收藏代码
  1. protected void determineCompressionMode() {  
  2.   if (fileNamePatternStr.endsWith(".gz")) {  
  3.     addInfo("Will use gz compression");  
  4.     compressionMode = CompressionMode.GZ;  
  5.   } else if (fileNamePatternStr.endsWith(".zip")) {  
  6.     addInfo("Will use zip compression");  
  7.     compressionMode = CompressionMode.ZIP;  
  8.   } else { // 如果后缀名不是.gz或.zip,不会启用压缩  
  9.     addInfo("No compression will be used");  
  10.     compressionMode = CompressionMode.NONE;  
  11.   }  
  12. }  


e. RollingFileAppender保证append的值为true,这样当天先写入的日志内容就不会丢失  

ch.qos.logback.core.rolling.RollingFileAppender类 的start()方法: 
Java代码   收藏代码
  1. if (!append) { // append为false时  
  2.   addWarn("Append mode is mandatory for RollingFileAppender");  
  3.   append = true// 改成true  
  4. }  


fprudent模式不支持file设定;如果启用了压缩,logback将不会记录日志  

ch.qos.logback.core.rolling.RollingFileAppender类  
的start()方法: 
Java代码   收藏代码
  1. if (isPrudent()) { // 安全模式,但效率低  
  2.   if (rawFileProperty() != null) {  
  3.     addWarn("Setting \"File\" property to null on account of prudent mode");  
  4.     setFile(null); // 取消file属性设置  
  5.   }  
  6.   if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) { // 启用了压缩  
  7.     addError("Compression is not supported in prudent mode. Aborting");  
  8.     return// 返回,不会进行后面的记录日志操作  
  9.   }  
  10. }  

本文转载自:http://czj4451.iteye.com/blog/1975937

共有 人打赏支持
小代码2016
粉丝 35
博文 311
码字总数 153495
作品 0
安阳
程序员

暂无相关文章

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 36分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 43分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 50分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 51分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 55分钟前 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 59分钟前 ⋅ 0

建造模式

《JAVA与模式》之建造模式

Cobbage ⋅ 今天 ⋅ 0

WePY框架开发的小程序如何在微信web开发者工具中运行起来

一、首先需要安装node.js,安装步骤如下: 首先下载安装包 https://nodejs.org/en/download/ 点击下载相应的zip版本 然后将文件夹解压到任意目录 比如我这里解压到了:C:\Program Files\node...

Helios51 ⋅ 今天 ⋅ 0

使用EnumSet 代替位域(32)

1、位域(Bit field):使用or 运算将几个常量合并到一个集合中 位操作,可以有效地执行 AND 、OR 这样的位操作 但是 位域比int 常量枚举缺点更多 2、java.util 包里面的EnumSet 类是有效的替...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部