Log4j2多Appender配置异常:控制台无日志输出排查
Log4j2控制台无日志输出的问题分析与修复
问题场景
配置了包含ConsoleAppender和KafkaAppender的Log4j2.xml,期望:
- 所有级别日志输出至控制台
- 仅INFO及以上级别日志输出至Kafka
但实际控制台无日志输出。基于具体类/包名的Logger配置可正常工作,但需将配置作为可复用组件,不想指定具体类名。
原配置代码
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%date %-5level %logger - %msg"/> </Console> <Kafka name="KafkaAppender" topic="cdf-databricks-log"> <JsonTemplateLayout eventTemplateUri="classpath:JsonLayout.json"> <EventTemplateAdditionalField key="info" format="JSON" value='{"$resolver": "map"}' /> </JsonTemplateLayout> <Property name="bootstrap.servers">${env:KAFKA_HOST}:${env:KAFKA_PORT}</Property> <Property name="security.protocol">SASL_SSL</Property> <Property name="sasl.mechanism">PLAIN</Property> <Property name="sasl.jaas.config">org.apache.kafka.common.security.plain.PlainLoginModule required username="${env:KAFKA_USER}" password="${env:KAFKA_PASSWD};"</Property> </Kafka> <Async name="AsyncAppender"> <AppenderRef ref="KafkaAppender"/> </Async> </Appenders> <Loggers> <Root> <AppenderRef ref="ConsoleAppender" level="ALL"/> <AppenderRef ref="KafkaAppender" level="INFO"/> </Root> <!-- Do not let org.apache.kafka log to a Kafka appender on DEBUG level. That will cause recursive logging --> <Logger name="org.apache.kafka" level="WARN" /> </Loggers> </Configuration>
问题原因
- Root Logger未设置级别:Log4j2中Root Logger默认级别为
ERROR,仅会接收ERROR及以上级别的日志。虽然ConsoleAppender的AppenderRef设置了level="ALL",但Root Logger的前置过滤会先拦截掉ERROR以下的日志(如INFO、DEBUG),导致控制台无法输出这些日志。 - AsyncAppender未被使用:配置中定义了AsyncAppender用于异步发送Kafka日志,但Root Logger直接引用KafkaAppender,会导致同步发送日志可能阻塞主线程,不过这不是控制台无输出的直接原因。
修复后的配置
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%date %-5level %logger - %msg"/> </Console> <Kafka name="KafkaAppender" topic="cdf-databricks-log"> <JsonTemplateLayout eventTemplateUri="classpath:JsonLayout.json"> <EventTemplateAdditionalField key="info" format="JSON" value='{"$resolver": "map"}' /> </JsonTemplateLayout> <Property name="bootstrap.servers">${env:KAFKA_HOST}:${env:KAFKA_PORT}</Property> <Property name="security.protocol">SASL_SSL</Property> <Property name="sasl.mechanism">PLAIN</Property> <Property name="sasl.jaas.config">org.apache.kafka.common.security.plain.PlainLoginModule required username="${env:KAFKA_USER}" password="${env:KAFKA_PASSWD};"</Property> </Kafka> <Async name="AsyncAppender"> <AppenderRef ref="KafkaAppender"/> </Async> </Appenders> <Loggers> <!-- 给Root Logger设置最低级别ALL,确保所有日志都能被接收 --> <Root level="ALL"> <AppenderRef ref="ConsoleAppender" level="ALL"/> <!-- 引用AsyncAppender实现异步发送Kafka日志,同时通过level控制仅INFO及以上输出 --> <AppenderRef ref="AsyncAppender" level="INFO"/> </Root> <Logger name="org.apache.kafka" level="WARN" /> </Loggers> </Configuration>
关键修复点
- 给
<Root>节点添加level="ALL",让Root Logger接收所有级别的日志,再通过AppenderRef的level属性控制每个Appender的输出级别。 - 将Kafka的AppenderRef改为引用
AsyncAppender,利用异步发送避免阻塞,同时保持level="INFO"过滤仅输出INFO及以上级别的日志到Kafka。
内容的提问来源于stack exchange,提问作者Prabal Rakshit
相关产品推荐
相关产品推荐

