Logback totalSizeCap不生效

  |  
阅读次数
  |  
字数 712
  |  
时长 ≈ 3 分钟

问题描述

项目使用logback作为日志管理框架。

logback project

logback index

logback issues

这几天发现线上的info日志文件,总大小超过了设定阈值,仍然没删除掉旧文件,但是error日志却如期删除了。
info级别的日志,totalSizeCap为5G

1
2
3
4
5
6
7
8
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${logger.path}/info.%d{yy-MM-dd}.%i.log
</fileNamePattern>
<maxHistory>6</maxHistory>
<maxFileSize>1GB</maxFileSize>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>

error级别的日志,totalSizeCap为2G

1
2
3
4
5
6
7
8
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${logger.path}/error.%d{yy.MM.dd}.%i.log
</fileNamePattern>
<maxHistory>6</maxHistory>
<maxFileSize>1GB</maxFileSize>
<totalSizeCap>2GB</totalSizeCap>
</rollingPolicy>

经过排查发现是使用的版本刚好有一个这样的bug所导致的。

问题排查

根据totalSizeCap关键字,查找源码,可以看到以下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void capTotalSize(Date now) {
int totalSize = 0;
int totalRemoved = 0;
for (int offset = 0; offset < maxHistory; offset++) {
Date date = rc.getEndOfNextNthPeriod(now, -offset);
File[] matchingFileArray = getFilesInPeriod(date);
descendingSortByLastModified(matchingFileArray);
for (File f : matchingFileArray) {
long size = f.length();
if (totalSize + size > totalSizeCap) {
addInfo("Deleting [" + f + "]" + " of size " + new FileSize(size));
totalRemoved += size;
f.delete();
}
totalSize += size;
}
}
addInfo("Removed " + new FileSize(totalRemoved) + " of files");
}

此代码正是Logback用于删除总日志文件大小超过指定阈值时,进行删除最旧文件的方法所在。
自己本地打断点以及查看这个逻辑好像都不存在问题,经过一番排查后在最新版的源码里看到了该方法的异同之处。
最新的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void capTotalSize(Date now) {
long totalSize = 0;
long totalRemoved = 0;
for (int offset = 0; offset < maxHistory; offset++) {
Date date = rc.getEndOfNextNthPeriod(now, -offset);
File[] matchingFileArray = getFilesInPeriod(date);
descendingSort(matchingFileArray, date);
for (File f : matchingFileArray) {
long size = f.length();
if (totalSize + size > totalSizeCap) {
addInfo("Deleting [" + f + "]" + " of size " + new FileSize(size));
totalRemoved += size;
f.delete();
}
totalSize += size;
}
}
addInfo("Removed " + new FileSize(totalRemoved) + " of files");
}

两处代码的不同之处来自与前面两个字段类型的定义,一个是int一个是long,看到这里焕然大悟!int类型的最大值 Integer.MAX_VALUE2147483647,这样折算下来在以上第一段代码所示,如totalSizeCap值设置超过2G时,同时maxHistory内的文件大小累计到大于或等于Integer.MAX_VALUE时,该值将一直不会改变,也就是totalSize + size > totalSizeCap条件将永不成立,所以会导致在totalSizeCap设置超过2G时,不会删除旧日志文件的问题。
这里合理的代码为,将int类型的变量定义改为long类型,即第二段代码。

解决问题

知道了是bug了之后,就需要查看该问题在哪个版本进行了修复,然后将线上版本升级为fix掉该bug的版本。

点击该类History查看历史修改版本,可以看到这个问题已经有人提出过issue,并且fix掉之后提供了修复版了。