如何修复Log4j2的Appender递归调用错误?
问题场景
你已经完成了从Log4j到Log4j2的迁移,所有配置都按Log4j2标准调整了文件名和语法,但在添加针对pl.package.x或pl.package.y的Logger后,遇到了ERROR Recursive call to appender RootConsole的错误。有意思的是,当把该Logger的additivity设为false时一切正常,设为true就会触发错误。
你添加自定义Logger后的配置如下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="RootConsole" target="SYSTEM_OUT"> <PatternLayout pattern="%d{ISO8601} %c{1} [%t] %p - %m%n"/> </Console> <RollingFile name="IntegrationTestFile" fileName="it_test.log" filePattern="integration_test.log.%i"> <PatternLayout pattern="%d{ISO8601} %c{1} [%t] %p - %m%n"/> <Policies> <SizeBasedTriggeringPolicy size="100 KB"/> </Policies> <DefaultRolloverStrategy max="1"/> </RollingFile> </Appenders> <Loggers> <Root level="DEBUG"> <AppenderRef ref="RootConsole"/> <AppenderRef ref="IntegrationTestFile"/> </Root> <!-- 新增的引发错误的Logger --> <Logger name="pl.package.x" level="DEBUG" additivity="true"> <AppenderRef ref="RootConsole"/> <AppenderRef ref="IntegrationTestFile"/> </Logger> </Loggers> </Configuration>
递归调用错误的原因
咱们来拆解Log4j2的日志事件流转逻辑:
- 当
additivity="true"(这是默认值)时,子Logger处理完一条日志事件后,会把同一个事件传递给它的父Logger链,最终会传到Root Logger。 - 你的自定义
pl.package.xLogger和Root Logger,都配置了向完全相同的两个Appender输出:RootConsole和IntegrationTestFile。
这就导致了一个重复处理的场景:日志事件先被自定义Logger的两个Appender处理一遍,然后通过additivity机制传递给Root Logger,Root Logger又会把同一个事件再次发给这两个Appender。Log4j2内部有检测机制,防止同一个日志事件被同一个Appender重复处理,这种重复触发的情况会被判定为递归调用,于是就抛出了错误。
修复方案
根据你的需求,这里有两种简单有效的修复方式:
方案1:保持additivity="false"(推荐)
既然你的自定义Logger已经把事件输出到目标Appender了,完全没必要让Root Logger再重复输出一次。设置additivity="false"可以切断事件向父Logger的传递,既解决了递归错误,还能避免日志重复打印:
<Logger name="pl.package.x" level="DEBUG" additivity="false"> <AppenderRef ref="RootConsole"/> <AppenderRef ref="IntegrationTestFile"/> </Logger>
方案2:移除自定义Logger中的Appender引用
如果你确实需要additivity="true"(比如希望Root Logger的其他Appender也能收到这个事件),那自定义Logger就不需要自己绑定Appender,让事件自然传递到Root Logger,由Root统一处理输出即可:
<Logger name="pl.package.x" level="DEBUG" additivity="true"> <!-- 这里不添加AppenderRef,事件会自动传给Root Logger处理 --> </Logger>
这样既保留了事件向上传递的能力,又不会让同一个Appender处理重复事件,递归错误自然就不会出现了。
内容的提问来源于stack exchange,提问作者Szymon Gross

