我有一个使用 log4j 进行日志记录的 Java 应用程序。一切都很好,直到 log4Shell 出现问题,我被迫升级到 2.17.1。
我的应用程序使用基于启动、时间和大小的滚动策略。通常它每天会生成大约 6 个日志文件。但有些时候事情变得非常疯狂(我最需要这些日志文件),文件数量可能一天超过 100 个。程序不断崩溃,看门狗不断将其唤醒。
之前运行的版本除了 log4j 版本之外没有任何变化,在固定数字(可能是 100)之后开始覆盖最后一个日志文件。我开始在文件名中使用 %04i,因此我得到了可读性良好的循环数字。我当前的配置不再丢弃最后一个文件,但发生了以下情况:
-rw-r--r-- 1 xxxxxxx xx 588 Mar 8 17:08 TRACE.2022-03-08-17.0096.log
-rw-r--r-- 1 xxxxxxx xx 213 Mar 8 17:08 TRACE.2022-03-08-17.0097.log
-rw-r--r-- 1 xxxxxxx xx 588 Mar 8 17:09 TRACE.2022-03-08-17.0098.log
-rw-r--r-- 1 xxxxxxx xx 213 Mar 8 17:09 TRACE.2022-03-08-17.0099.log
-rw-r--r-- 1 xxxxxxx xx 65619 Mar 8 17:26 TRACE.2022-03-08-17.0100.log
当值为 100 时,log4j 便会停止循环。
文档中没有提到任何此类限制。这是怎么回事?
以下是我最新的配置。该应用程序是一个最小示例,文件大小仅为 500 字节,旨在按小时而不是天重新启动循环,但原则仍然适用。
该配置也是触发器和滚动策略、文件名模式和附加程序组合的众多变体中的一个示例。我尝试过的所有方法都遇到了这个限制。
我可以想出一些解决方法,但我更希望更好地了解问题的原因。如果您能提供任何见解或建议,我将不胜感激。
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Configuration status="WARN">
3 <Appenders>
4 <RollingFile name="TRACE"
5 filePattern="./trace/TRACE.%d{YYYY-MM-dd-HH}.%04i.log">
6 <!-- ex-fileName= "./trace/TRACE.log" -->
7 <Policies>
8 <OnStartupTriggeringPolicy />
9 <SizeBasedTriggeringPolicy size="500 B" />
10 <TimeBasedTriggeringPolicy />
11 <!-- CronTriggeringPolicy schedule="0 0 * * * ?" / -->
12 </Policies>
13 <DirectWriteRolloverStrategy />
14 <PatternLayout>
15 <header>%d{ISO8601} ---------- Trace file started. ----------\n</header>
16 <footer>%d{ISO8601} ----------- Trace file ended. -----------\n</footer>
17 <Pattern>%d{ISO8601} [%-4.-4t %-15.-15M#%4L] %-5level %msg%n%xEx{full}</Pattern>
18 </PatternLayout> "/>
19 </RollingFile>
20 </Appenders>
21 <Loggers>
22 <Root level="error">
23 <AppenderRef ref="TRACE"/>
24 </Root>
25 <Logger name="minimal" level="trace" additivity="false">
26 <AppenderRef ref="TRACE"/>
27 </Logger>
28 </Loggers>
29 </Configuration>
答案1
我认为%04i
防止翻车的想法似乎是有道理的。
在标签内添加<RollingFile>
条目
<DefaultRolloverStrategy max="200"/>
帮助绕过了 100 的限制。
您可以选择一个较大的最大限制,并采用一些清理方法作为解决方法。
根据文档
附加程序,也存在一个nomax
可能有帮助的论点。
答案2
通过 @harrymc 的一些有用提示和一些实验,我现在相信我正在查看 log4j 中的一个错误,或者至少是一个文档不足的情况。以下是我的测试结果,每个测试的参数RollingFileAppender.filePattern
和 xxx都有一些变化RolloverStrategy
:
- 如果
filePattern
包含%06i
,则循环在 100 之后中断。 - 如果
filePattern
包含%006i
,它也会在 100 之后中断。 - 如果
filePattern
包含%6i
,它会在 10 之后中断。 - 如果
filePattern
包含%06i
且DefaultRolloverStrategy.min
=10000、max
=99999,则仅在 1 之后中断。 - 设置
DefaultRolloverPattern.fileIndex
为nomax
不会改变上述内容。 filePattern
如果包含,文件循环就可以正常工作%i
。
现在确实如此log4j 文档仅提到“%i”作为数字循环索引的格式说明符,所以我猜从技术上讲这不是一个错误。不过,我发现像 Cprintf
或 Java 的s
String.format() 函数那样指定字段宽度和前导零是有问题的似乎按预期工作,直到获得异常大的循环数(超过 100)。
log4j 的文档RollingRandomAccessFileAppender明确推荐索引格式规范的修饰符:
... 和/或 %i 表示整数计数器。整数计数器允许指定填充,例如 %3i 用于将计数器用空格填充为 3 位数字,或(通常更有用)%03i 用于将计数器用零填充为 3 位数字。
这让我想知道为什么这两个非常相似的附加器对索引参数的处理有所不同。
更新:我已提交错误报告:https://issues.apache.org/jira/browse/LOG4J2-3432