实际生产中,每天都有大量的日志生成,单个文件(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. <root level="DEBUG">
  14. <appender-ref ref="rollingAppender" />
  15. </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. public String getFile() {
  6. return rollingPolicy.getActiveFileName(); // 从滚动策略获取
  7. }

上面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. public String getParentsRawFileProperty() {
  11. return parent.rawFileProperty();
  12. }

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. if (rollingPolicy == null) {
  9. addError("No RollingPolicy was set for the RollingFileAppender named "
  10. + getName());
  11. addError("For more information, please visit "+CODES_URL+"rfa_no_rp");
  12. return;
  13. }

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. String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
  6. if (compressionMode == CompressionMode.NONE) {
  7. if (getParentsRawFileProperty() != null) {
  8. renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); // file指定,重命名为fileNamePattern格式。如果目标文件存在,则重命名失败
  9. } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }
  10. } else {
  11. if (getParentsRawFileProperty() == null) {
  12. future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem); // file未指定,异步压缩
  13. } else {
  14. future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem); // file指定,重命名并异步压缩
  15. }
  16. }
  17. if (archiveRemover != null) {
  18. archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); // 删除历史日志
  19. }
  20. }

默认的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. public void setMaxHistory(int maxHistory) {
  14. // 待删除日志的终止日期:回退(maxHistory+1)天
  15. this.periodOffsetForDeletionTarget = -maxHistory - 1;
  16. }

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. }

f. prudent模式不支持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

logback之三:输出日志到文件(滚动)相关推荐

  1. logback异步输出日志详解

    前言 logback应该是目前最流行的日志打印框架了,毕竟Spring Boot中默认的集成的日志框架也是logback.在实际项目开发过程中,常常会遇到由于打印大量日志而导致程序并发降低,QPS降低 ...

  2. logcat 实时输出日志到文件(logcat输出日志到文件、同时包括多个TAG)

    adb logcat -v time -f /sdcard/test.txt -s "TAG:*" 说明:1, -v time表示日志的输出日志,默认导出来是没时间的2, -f 后 ...

  3. logback系列之二:输出日志到文件

    2019独角兽企业重金招聘Python工程师标准>>> 和 logback系列之一:输出日志到控制台 类似,改动的地方: 1. logback[-test].xml文件: Java代 ...

  4. Log4net 中输出日志到文件,文件名根据日期生成

    1           简介 1.1          Log4net的优点: 几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管 ...

  5. python输出日志到文件_【已解决】Python中,如何让多个py文件的logging输出到同一个日志log文件...

    [问题] 有一个比较长的python脚本文件,其中关于log日志输出,用的是logging,对应初始化代码为:logging.basicConfig( level = logging.DEBUG, f ...

  6. python3 logging输出到文件_python3:logging模块 输出日志到文件

    python自动化测试脚本运行后,想要将日志保存到某个特定文件,使用python的logging模块实现 参考代码: importloggingdefinitLogging(logFilename,e ...

  7. maven使用slf4j输出日志到文件

    log4j.properties ### set log levels ### log4j.rootLogger=debug, stdout, D, E #ConsoleAppender,控制台输出 ...

  8. nohup 输出日志到文件_超详细的EFK安装部署教程--filebeat日志数据采集

    概述 Filebeat是本地文件的日志数据采集器. 作为服务器上的代理安装,Filebeat监视日志目录或特定日志文件,tail file,并将它们转发给Elasticsearch或Logstash进 ...

  9. logback系列之四:输出日志到不同文件

    实际生产中,每天都有大量的日志生成,单个文件(FileAppender)已经不能满足要求,RollingFileAppender继承了FileAppender,并提供了更多的功能: 每天生成一个日志文 ...

最新文章

  1. java jdk1.8环境变量的配置
  2. 在 Virt-manager 图形界面中使用桥接网络
  3. JNDI数据源配置注意事项
  4. java中间件_Java技术分享:一致性更强的分布式数据库中间件
  5. nginx 解析php漏洞
  6. PyQt5-菜单栏工具栏状态栏的使用(QMenuBar、QToolBar、QStatusBar)
  7. 侍魂胧月传说显示服务器未开启,侍魂胧月传说为什么进不去 侍魂胧月传说进不去的原因...
  8. android opencv 识别文字_基于SpringBoot的车牌识别系统(附项目地址)
  9. git21天打卡day20-合并分支
  10. 12.TCP/IP 详解卷1 --- 广播和多播
  11. setValue:forKey of nsobject
  12. 算法分析与设计实验报告二——贪心算法实验
  13. Python Text Processing with NLTK 2.0 Cookbook代码笔记
  14. 第二周:1.逆序的三位数(5分)(题目来源中国大学MOOC)
  15. ASEMI场效应管7N60的极限和静态参数详解
  16. 示波器基础知识100问
  17. 微信小程序使用高德SDK获取天气
  18. Python_Python遍历列表的四种方法
  19. MFC添加加瓦系列一MFC编写的增量更新软件
  20. Java第二课:图形界面(实现QQ登陆界面)

热门文章

  1. 2020电赛芯片介绍和题目估计(二):LMT70
  2. ARM® Cortex®-M内核单片机STM32家族介绍,覆盖STM32F、STM32H、STM32L全系列
  3. beeline安装_Beeline使用
  4. 互联网晚报 | 7月9日 星期六 |马斯克终止收购推特;​B 站回应 2 亿余条用户账号疑泄露传闻;上海逐步开放电影院和演出场所...
  5. Kaop打印项之表格
  6. JAVA计算机毕业设计喜枫日料店自助点餐系统(附源码、数据库)
  7. vue中的一个子组件如何在父组件中调动另一个子组件中的方法
  8. 速度收藏!史上最全Spring 面试题 92 问!【附答案】高清PDF下载
  9. Android屏幕上涂鸦画笔标记的实现
  10. 0926物体检测和数据集