问题是新增了错误日志,然后在logback-spring,log中增加了对应的配置,由于说要接入企微机器人,希望能把名称都命名为带日期的,仔细阅读文档发现只要不配置file文件名即可.于是进行了如下配置
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件输出格式 -->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- ThresholdFilter过滤低于指定阈值的事件。 对于等于或高于阈值的事件,ThresholdFilter将在调用其decision()方法时响应NEUTRAL。
但是,将拒绝级别低于阈值的事件 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level><!-- 低于ERROR级别的日志(debug,info)将被拒绝,等于或者高于ERROR的级别将相应NEUTRAL -->
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}_error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!--单个日志文件的最大体积-->
<maxFileSize>${LOG_FILE_MAX_SIZE:-20MB}</maxFileSize>
<!-- 日志最大的历史 30天 -->
<maxHistory>${LOG_FILE_MAX_HISTORY:-30}</maxHistory>
</rollingPolicy>
</appender>
<logger name="com.example" level="INFO">
<appender-ref ref="ERROR_LOG"/>
</logger>
配置完成后,确实正常的生成了每天的日志文件带日期,但是遇到一个问题,就是当第二天(第三天都可,不是当天就行)没有错误日志写入触发压缩时,这时如果重启服务,启动时不会触发压缩,只会生成新的一个带当天日期的文件,问题就来了,之前的那个文件就一直在那里,不压缩.
为了解决这个问题,看文档,还是没找到,后来debug到服务启动时不会触发压缩,只有新的日志写入才会触发压缩
附上源码中的压缩的方法
ch.qos.logback.core.rolling.RollingFileAppender#rollover
public void rollover() {
lock.lock();
try {
// Note: This method needs to be synchronized because it needs exclusive
// access while it closes and then re-opens the target file.
//
// make sure to close the hereto active log file! Renaming under windows
// does not work for open files.
this.closeOutputStream();
attemptRollover();
attemptOpenFile();
} finally {
lock.unlock();
}
}
解决方式就是配置一个file,只能最新的日志暂不加日期了
<file>${LOG_FILE}_error.log</file>
与此同时发现logback-spring.xml不会在jar包启动时spring.config.location指定位置,
可以通过application.yml中的logging.config指定位置
如果不需要读spring的配置也可通过logback.configurationFile配置指定
logback当配置maxHistory为30时究竟是什么时候触发删除之前的日志呢?
分两种情况,第一种是配置cleanHistoryOnStart为true时(该配置默认为false),在服务启动时就会触发删除
第二种情况,就是没有配置,或者配置为false时,和触发滚动压缩一样,也是在有日志写入文件中才会触发,调用ch.qos.logback.core.rolling.TimeBasedRollingPolicy#rollover时
public void rollover() throws RolloverFailure {
// when rollover is called the elapsed period's file has
// been already closed. This is a working assumption of this method.
String elapsedPeriodsFileName = timeBasedFileNamingAndTriggeringPolicy.getElapsedPeriodsFileName();
String elapsedPeriodStem = FileFilterUtil.afterLastSlash(elapsedPeriodsFileName);
if (compressionMode == CompressionMode.NONE) {
if (getParentsRawFileProperty() != null) {
renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName);
} // else { nothing to do if CompressionMode == NONE and parentsRawFileProperty == null }
} else {
if (getParentsRawFileProperty() == null) {
compressionFuture = compressor.asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elapsedPeriodStem);
} else {
compressionFuture = renameRawAndAsyncCompress(elapsedPeriodsFileName, elapsedPeriodStem);
}
}
//此处就是调用清除日志的方法
if (archiveRemover != null) {
Date now = new Date(timeBasedFileNamingAndTriggeringPolicy.getCurrentTime());
this.cleanUpFuture = archiveRemover.cleanAsynchronously(now);
}
}
this.cleanUpFuture = archiveRemover.cleanAsynchronously(now);该方法实际上只给线程池中提交了一个任务,真正实现清除的是ch.qos.logback.core.rolling.helper.TimeBasedArchiveRemover#clean方法,如下
public void clean(Date now) {
long nowInMillis = now.getTime();
// for a live appender periodsElapsed is expected to be 1
int periodsElapsed = computeElapsedPeriodsSinceLastClean(nowInMillis);
lastHeartBeat = nowInMillis;
if (periodsElapsed > 1) {
addInfo("Multiple periods, i.e. " + periodsElapsed + " periods, seem to have elapsed. This is expected at application start.");
}
for (int i = 0; i < periodsElapsed; i++) {
int offset = getPeriodOffsetForDeletionTarget() - i;
Date dateOfPeriodToClean = rc.getEndOfNextNthPeriod(now, offset);
cleanPeriod(dateOfPeriodToClean);
}
}
计算一个周期32天的分钟数46080和14*24=336(14天24小时)取较小的值,然后循环这个对应的次数,去掉-maxHistory - 1加上次数数,然后根据这个偏移量和当前时间获取要清理的日期,用这个日期获取文件,并删除文件