logback系列之四:输出日志到不同文件
实际生产中,每天都有大量的日志生成,单个文件(FileAppender)已经不能满足要求,RollingFileAppender继承了FileAppender,并提供了更多的功能:
- 每天生成一个日志文件
- 将前一天的日志重命名为包含日期的格式
- 根据需要,删除过期历史日志
配置
和 logback系列之二:输出日志到文件 类似,改动的地方:
1. logback[-test].xml文件:
- <appender name="rollingAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>/logs/heuristic.log</file>
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>/logs/heuristic-%d{yyyy-MM-dd}.log</fileNamePattern>
- <maxHistory>30</maxHistory>
- </rollingPolicy>
- <encoder><!-- 必须指定,否则不会往文件输出内容 -->
- <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
- </encoder>
- <append>false</append>
- <prudent>false</prudent>
- </appender>
- <root level="DEBUG">
- <appender-ref ref="rollingAppender" />
- </root>
调用测试类的方法,生成heuristic-2013-11-16.log文件。
源码分析
a. 如果指定了file属性,当天的文件名为file属性值(/logs/heuristic.log):
ch.qos.logback.core.rolling.RollingFileAppender类
- public void start() {
- ...
- currentlyActiveFile = new File(getFile()); // 获取日志文件名
- }
- public String getFile() {
- return rollingPolicy.getActiveFileName(); // 从滚动策略获取
- }
上面logback[-test].xml的rollingPolicy配置为
ch.qos.logback.core.rolling.TimeBasedRollingPolicy类
看下实现:
- public String getActiveFileName() {
- String parentsRawFileProperty = getParentsRawFileProperty();
- if (parentsRawFileProperty != null) { // logback.xml指定了file属性
- return parentsRawFileProperty; // 使用file值
- } else {
- return timeBasedFileNamingAndTriggeringPolicy
- .getCurrentPeriodsFileNameWithoutCompressionSuffix();
- }
- }
- public String getParentsRawFileProperty() {
- return parent.rawFileProperty();
- }
ch.qos.logback.core.FileAppender类
- final public String rawFileProperty() {
- return fileName;
- }
b. 必须指定TriggeringPolicy<E>和RollingPolicy,否则不会打印日志:
看下
ch.qos.logback.core.rolling.RollingFileAppender类 :
- public void start() {
- if (triggeringPolicy == null) {
- addWarn("No TriggeringPolicy was set for the RollingFileAppender named "
- + getName());
- addWarn("For more information, please visit "+CODES_URL+"#rfa_no_tp");
- return;
- }
- if (rollingPolicy == null) {
- addError("No RollingPolicy was set for the RollingFileAppender named "
- + getName());
- addError("For more information, please visit "+CODES_URL+"rfa_no_rp");
- return;
- }
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方法:
- public void rollover() throws RolloverFailure {
- // 当此方法调用时,假定前一天日志文件已经关闭
- String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy
- .getElapsedPeriodsFileName();
- String elpasedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
- if (compressionMode == CompressionMode.NONE) {
- if (getParentsRawFileProperty() != null) {
- renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName); // file指定,重命名为fileNamePattern格式。如果目标文件存在,则重命名失败
- } // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }
- } else {
- if (getParentsRawFileProperty() == null) {
- future = asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elpasedPeriodStem); // file未指定,异步压缩
- } else {
- future = renamedRawAndAsyncCompress(elapsedPeriodsFileName, elpasedPeriodStem); // file指定,重命名并异步压缩
- }
- }
- if (archiveRemover != null) {
- archiveRemover.clean(new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime())); // 删除历史日志
- }
- }
默认的archiveRemover为 ch.qos.logback.core.rolling.helper.DefaultArchiveRemover抽象类 :
- public void clean(Date now) {
- long nowInMillis = now.getTime();
- int periodsElapsed = computeElapsedPeriodsSinceLastClean(nowInMillis);
- lastHeartBeat = nowInMillis;
- if (periodsElapsed > 1) {
- addInfo("periodsElapsed = " + periodsElapsed);
- }
- // 从待删除日志的终止日期开始,每次回退一天,删除过期日志
- for (int i = 0; i < periodsElapsed; i++) {
- cleanByPeriodOffset(now, periodOffsetForDeletionTarget - i);
- }
- }
- public void setMaxHistory(int maxHistory) {
- // 待删除日志的终止日期:回退(maxHistory+1)天
- this.periodOffsetForDeletionTarget = -maxHistory - 1;
- }
cleanByPeriodOffset为抽象方法,这里交由
ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover子类 实现:
- protected void cleanByPeriodOffset(Date now, int periodOffset) {
- Date date2delete = rc.getRelativeDate(now, periodOffset); // 计算需要删除日志的日期
- String filename = fileNamePattern.convert(date2delete);
- File file2Delete = new File(filename);
- if (file2Delete.exists() && file2Delete.isFile()) {
- file2Delete.delete(); // 删除文件
- addInfo("deleting " + file2Delete);
- if (parentClean) {
- removeFolderIfEmpty(file2Delete.getParentFile());
- }
- }
- }
d. 如果要启用压缩,需要将fileNamePattern的后缀名设置为压缩格式,如:/logs/heuristic-%d{yyyy-MM-dd}.zip。
看下 ch.qos.logback.core.rolling.RollingPolicyBase类 相关的代码:
- protected void determineCompressionMode() {
- if (fileNamePatternStr.endsWith(".gz")) {
- addInfo("Will use gz compression");
- compressionMode = CompressionMode.GZ;
- } else if (fileNamePatternStr.endsWith(".zip")) {
- addInfo("Will use zip compression");
- compressionMode = CompressionMode.ZIP;
- } else { // 如果后缀名不是.gz或.zip,不会启用压缩
- addInfo("No compression will be used");
- compressionMode = CompressionMode.NONE;
- }
- }
e. RollingFileAppender保证append的值为true,这样当天先写入的日志内容就不会丢失:
ch.qos.logback.core.rolling.RollingFileAppender类 的start()方法:
- if (!append) { // append为false时
- addWarn("Append mode is mandatory for RollingFileAppender");
- append = true; // 改成true
- }
f. prudent模式不支持file设定;如果启用了压缩,logback将不会记录日志:
ch.qos.logback.core.rolling.RollingFileAppender类
的start()方法:
- if (isPrudent()) { // 安全模式,但效率低
- if (rawFileProperty() != null) {
- addWarn("Setting \"File\" property to null on account of prudent mode");
- setFile(null); // 取消file属性设置
- }
- if (rollingPolicy.getCompressionMode() != CompressionMode.NONE) { // 启用了压缩
- addError("Compression is not supported in prudent mode. Aborting");
- return; // 返回,不会进行后面的记录日志操作
- }
- }
logback系列之四:输出日志到不同文件相关推荐
- logback之三:输出日志到文件(滚动)
实际生产中,每天都有大量的日志生成,单个文件(FileAppender)已经不能满足要求,RollingFileAppender继承了FileAppender,并提供了更多的功能: 每天生成一个日志文 ...
- 大剑无锋之后台运行程序并输出日志到某文件【面试推荐】
第一种: # ./pso > pso.file 2>&1 & 解释:将pso直接放在后台运行,并把终端输出存放在当前目录下的pso.file文件中. 当客户端关机后重新登陆 ...
- logback系列之二:输出日志到文件
2019独角兽企业重金招聘Python工程师标准>>> 和 logback系列之一:输出日志到控制台 类似,改动的地方: 1. logback[-test].xml文件: Java代 ...
- slf4j + logback 输出日志:mybatis sql语句
1 引入jar包:maven resposity 中 选择logback classic module <dependency> <groupId>ch.qos.logback ...
- log4j和logback的冲突导致日志输出异常
2019独角兽企业重金招聘Python工程师标准>>> 前一阵在在项目中碰到一个日志问题.工程使用的是log4j,log4j.xml中也配置了工程日志路径和策略,并把日志级别定为wa ...
- Spring Boot 使用 Log4j2 Logback 输出日志到 EKL
文章目录 1.ELK 介绍 2.环境.软件准备 3.ELK 环境搭建 4.Spring Boot 配置示例 4.1.Log4j2 方式配置 4.2.Logback 方式配置 1.ELK 介绍 ELK ...
- logback之二:输出日志到控制台
和logack之一:输出日志到控制台 类似,改动的地方: 1. logback[-test].xml文件: Java代码 <appender name="fileAppender& ...
- python 日志输出为json格式文件_Py修行路 python基础 (二十一)logging日志模块 json序列化 正则表达式(re)...
一.日志模块 两种配置方式:1.config函数 2.logger #1.config函数 不能输出到屏幕 #2.logger对象 (获取别人的信息,需要两个数据流:文件流和屏幕流需要将数据从两个数据 ...
- logback出现大量XXX_IS_UNDEFINED日志文件的问题
前言 在spring boot中采用logback将日志打印到文件时,你是否遇到过文件名为XXX_IS_UNDEFINED的情况,今天带大家一块分析解决这个问题. 一.logback中spring属性 ...
最新文章
- centos的nginx支持ssl
- Java中抽象类和接口
- jquery1.9+获取append后的动态元素
- ReactNative 导航栏Navigator的使用及参数navigator的传递
- html查看今天星期几,jquery怎么获取星期几
- synchronized实现原理之---Moniter的实现原理
- Allegro对不规则outline处理
- 智能座舱之HUD-发展趋势深度解析
- OSPF多实例路由防环检测功能介绍
- 使用visio来进行画类图
- wps表格怎么按特定的顺序对数据进行排序
- 2020040920200418知交零落实是人生常态
- 怎么写功能测试报告,分享专业的功能报告模板
- 光伏辐照和发电功率数据集
- 大数据正在改变我们的生活
- ES的插入优化之bulk
- Oracle oo4o vs2010 c++
- Eclipse 简介和插件开发天气预报
- BDP数据可视化 - 散点图
- 中介分水岭 机构大数据风生水起
热门文章
- 2017 终点亦是起点
- matlab 工具箱 径向基,精确径向基(matlab工具箱)
- RA病人关节残障与软骨破坏而非骨破坏相关
- SSL2668 2017年8月7日提高组T1 根(dfs)
- 【Python学习笔记】6:用Gauss-Legendre求积公式近似求积分值
- Credly 数字证书
- PHP 文档标签添加 间隔符“多空格”处理
- 图的度序列:Havel定理
- python实现qq登录腾讯视频_QQ腾讯视频爬取和qv_rmt限速算法python版
- 金仓数据库KingbaseES客户端编程接口指南-ODBC(6. KingbaseES ODBC 的扩展属性)