Log4J2自定义级别日志重复输出问题求助
问题分析与解决方案
问题根源
你遇到的重复输出问题,核心是对Log4j2中AppenderRef的level属性功能理解有误:
- 该属性并非"仅输出指定级别的日志",而是设置Appender接收的最低级别阈值——只要日志级别对应的数值大于等于该阈值,就会被该Appender输出。
- 结合你自定义的级别数值:A(450) < B(460),在Log4j2中,数值越大代表级别越严重(比如标准级别INFO=20000、ERROR=40000),这意味着A是比B更低级别的日志。
当你输出A级别日志时:
- ConsoleAppender:Root级别为INFO,若A的实际数值>=INFO(你能输出说明是这种情况),则符合Root的级别要求,会输出。
- AppenderForB的
level="B"阈值是460,若你代码或配置中搞反了A、B的数值(比如A=460、B=450),A级别日志会满足AppenderForB的阈值条件,导致输出到B.log;反之如果A=450<B=460,理论上不会输出,但你的现象说明数值逻辑存在混淆。
同理,B级别日志会满足AppenderForA的阈值条件,输出到A.log。
正确解决方案
如果你需要让每个Appender仅输出对应级别的日志,必须使用精确级别匹配过滤器,而非依赖AppenderRef的level属性。修改配置如下:
1. 配置带LevelMatchFilter的Appender
<Appenders> <File name="AppenderForA" fileName="A.log"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <!-- 仅匹配A级别日志 --> <LevelMatchFilter level="A" onMatch="ACCEPT" onMismatch="DENY"/> </File> <File name="AppenderForB" fileName="B.log"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <!-- 仅匹配B级别日志 --> <LevelMatchFilter level="B" onMatch="ACCEPT" onMismatch="DENY"/> </File> <Console name="ConsoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <CustomLevels> <Level name="A" intLevel="45000"/> <!-- 调整数值到INFO以上,确保Root能处理 --> <Level name="B" intLevel="46000"/> </CustomLevels> <Root level="INFO"> <AppenderRef ref="ConsoleAppender"/> <AppenderRef ref="AppenderForA"/> <AppenderRef ref="AppenderForB"/> <!-- 移除AppenderRef上的level属性,由Appender内部的Filter控制 --> </Root> </Loggers>
2. 代码中确保自定义级别与配置一致
public class UserService1 { private static final Logger LOGGER = LogManager.getLogger(UserService1.class); // 复用配置中定义的级别,避免数值不一致 private static final Level LEVEL_A = Level.getLevel("A"); private static final Level LEVEL_B = Level.getLevel("B"); public void doSomething() { LOGGER.log(LEVEL_A, "This is a log message with Custom Level A."); LOGGER.log(LEVEL_B, "This is a log message with Custom Level B."); } }
关键说明
LevelMatchFilter的onMatch="ACCEPT"和onMismatch="DENY"确保只有匹配指定级别的日志才会被该Appender输出。- 调整自定义级别数值到INFO(20000)以上,确保Root的
INFO级别会处理这些日志;如果需要保留低数值,需将Root级别调整为TRACE或ALL。 - 代码中直接通过
Level.getLevel("A")获取配置中定义的级别,避免代码与配置的数值不一致导致的问题。
内容的提问来源于stack exchange,提问作者Tarun
相关产品推荐
相关产品推荐

