Log4j2滚动触发策略不生效 生成同名重复文件且压缩包损坏
问题根因
你遇到的双日志文件、压缩包损坏、大小超限问题由三类原因共同导致:
- 多写入端冲突:
RollingRandomAccessFile默认未开启文件锁,若存在多进程共用同一路径日志文件(同机多实例部署)、Web容器多类加载器加载多份Log4j2配置(多个Web应用引用独立Log4j2包且配置了同路径日志)的场景,会有多个日志上下文同时持有目标文件句柄。当其中一个上下文触发滚动、将原日志文件重命名准备压缩时,其他上下文会判定原日志文件丢失,直接创建新的同名未压缩日志继续写入;此时正在执行的压缩流程只能拿到部分文件内容,最终生成损坏的gz包,同时留下未压缩的重名日志副本。 - 旧版本Log4j2已知bug:2.17.0之前的版本中,若时间策略和大小策略的触发时机完全重叠(比如你配置了
modulate="true"对齐整点触发时间滚动,刚好整点时日志文件大小也达到250MB阈值),会在同进程内连续触发两次滚动操作,两次操作争抢文件资源,同样会导致文件重命名、压缩流程异常。 - 配置语义偏差:你当前
filePattern中的日期格式用单引号包裹了:00Z作为字面量硬编码,会干扰Log4j2对时间窗口边界的判定,跨时间窗口滚动时容易出现%i计数器命名冲突,进一步提升滚动异常概率。
另外你观察到的日志文件略超250MB属于策略正常表现:SizeBasedTriggeringPolicy的阈值校验发生在日志写入前,如果单条日志(如全量异常栈、大报文打印)大小超过当前文件剩余可写容量,写入后文件大小会略高于设定阈值,不属于配置错误。
修复方案
按以下顺序调整配置即可解决异常:
- 将Log4j2依赖升级到2.17.1及以上版本,修复双策略同时触发时的重复滚动bug。
- 在
RollingRandomAccessFile标签上增加append="true" fileLock="true"属性,启用进程级文件锁,避免多写入端同时操作文件导致的滚动冲突。 - 修正
filePattern的日期格式,移除硬编码的字面量,改用Log4j2原生日期格式规则,将filePattern值调整为logs/app-%d{yyyy-MM-dd'T'HH:mm:00Z}.%i.log.gz,保证时间窗口判定准确,避免计数器命名冲突。 - 若存在同机多实例部署场景,不要让多个实例写入同一路径的同名日志文件,给每个实例的日志文件名增加唯一实例标识,从根源上杜绝文件争抢。
- (可选)如果对日志文件大小限制要求严格,可以额外配置
directWriteLength参数限制单条日志的最大写入长度,避免单条超大日志导致文件大小超出阈值过多。
修正后的完整配置参考:
<RollingRandomAccessFile name="app_log" fileName="logs/app.log" filePattern="logs/app-%d{yyyy-MM-dd'T'HH:mm:00Z}.%i.log.gz" append="true" fileLock="true"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] [%X{opc-request-id}] %replace{%m}{[\n\r]+}{} %ex{full}{separator( | )}%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="60" modulate="true"/> <SizeBasedTriggeringPolicy size="250 MB"/> </Policies> <DefaultRolloverStrategy max="20"> <Delete basePath="logs/" followLinks="True"> <IfFileName glob="app-*.log*"> <IfAny> <IfLastModified age="14d"/> <IfAccumulatedFileSize exceeds="6 GB"/> </IfAny> </IfFileName> </Delete> </DefaultRolloverStrategy> </RollingRandomAccessFile>
内容的提问来源于stack exchange,提问作者codingNinja
相关产品推荐
相关产品推荐

