问题描述
研发突然反馈,生产日志没有按 Log4j2 设置的 30 天保存,并且今天的日志有一些丢失了。我们上去查看生产日志,看到今天的日志文件剩余 30 个,和 log4j2.yaml 配置文件对比,发现研发配置的 Log4j2 保存的规则是按个数,而不是按天数。
之前没发现这个问题,是因为刚上线,访问量不大,每天只产生的日志文件不多,没有达到设置的阈值,不会触发日志文件覆盖。
原因分析
当时生产环境的 Log4j2 配置大概如下。
yaml
Configuration:
Appenders:
RollingRandomAccessFile:
- name: INFO_FILE
fileName: ${LOG_PATH}/${APP_NAME}-info.log
filePattern: ${LOG_PATH}/${APP_NAME}-info-%d{yyyy-MM-dd}-%i.log.gz
ignoreExceptions: false
PatternLayout:
pattern: ${LOG_PATTERN}
Policies:
TimeBasedTriggeringPolicy:
modulate: true
interval: 1
SizeBasedTriggeringPolicy:
size: 50MB
DefaultRolloverStrategy:
max: 30 # 非期望的配置
在没有查阅的官方文档情况下,误以为 DefaultRolloverStrategy.max=30
是按天数存储的,实际上这个配置用于限制文件计数器 %i
的最大值,例如 info-%d{yyyy-MM-dd}-%i.log.gz
,当超过这个阈值,会删除旧的文件。
正确的配置应该是这样。
yaml
Configuration:
Appenders:
RollingRandomAccessFile:
- name: INFO_FILE
fileName: ${LOG_PATH}/${APP_NAME}-info.log
filePattern: ${LOG_PATH}/${APP_NAME}-info-%d{yyyy-MM-dd}-%i.log.gz
ignoreExceptions: false
PatternLayout:
pattern: ${LOG_PATTERN}
Policies:
CronTriggeringPolicy: # 低峰期定时触发
schedule: 0 0 3 * * ?
SizeBasedTriggeringPolicy: # 基于文件大小触发
size: 50MB
DefaultRolloverStrategy:
Delete: # 历史日志清除策略,保留 30 天内的日志
basePath: ${LOG_PATH} # 扫描目录
maxDepth: 1 # 扫描目录深度
IfFileName: # 匹配文件名
glob: ${APP_NAME}-info-*.log.gz
IfLastModified: # 保留一周
age: P7D # 符合期望的配置
故障复盘
配置即代码,日志配置应纳入代码审查范围,最好是出一个统一的日志配置方案,避免同类问题发生。关于 Log4j2 的配置,不要看网上的文章,大多数是没有经过实际验证的,最好的方式是查看官方文档,例如:logging.apache.org/log4j/2.x/m...