Log4j2分级别日志文件配置疑问:trace.log与debug.log为何包含INFO级日志
Log4j2分级别日志文件配置疑问:trace.log与debug.log为何包含INFO级日志
兄弟,这个问题我之前刚踩过一模一样的坑!核心原因其实是你对Log4j2的日志级别规则和配置逻辑有点误解,我给你掰扯清楚:
一、日志级别的“包含性”是核心误解
Log4j2的日志级别是有固定优先级的,从低到高排序是:TRACE < DEBUG < INFO < WARN < ERROR < FATAL。默认情况下,当你设置某个Logger或Appender的级别为DEBUG时,它会输出DEBUG及所有更高级别的日志(也就是DEBUG、INFO、WARN、ERROR、FATAL都会被打进去),而不是只输出DEBUG自己。同理,TRACE级别会包含TRACE、DEBUG、INFO、WARN、ERROR、FATAL所有日志——这就是你的trace.log和debug.log里出现INFO日志的直接原因!
二、RootLogger的配置放大了问题
再看你的RootLogger配置,它把所有分级别Appender(包括TRACE_LOG_FILE、DEBUG_LOG_FILE)都引用了,而且RootLogger的级别是ALL。这就意味着:
- RootLogger会把所有级别的日志(包括INFO)输出到TRACE_LOG_FILE(因为TRACE级别允许所有更高级别)
- 同时也会把DEBUG及以上的日志(包括INFO)输出到DEBUG_LOG_FILE
加上你单独配置的分级别Logger也会输出对应级别及以上的日志,等于同一条INFO日志被重复输出到了trace.log、debug.log和info.log里,混乱感拉满。
三、正确的分级别日志配置方案
要实现“每个日志文件只存对应级别日志”的需求,你需要做三个关键调整,我把修改后的完整配置给你:
# 定义统一日志格式 property.pattern = %d [%t] %F %-5L %-5p %c - %m%n # 控制台全量日志Appender appender.0.type = Console appender.0.name = ALL_LOG_CONSOLE appender.0.layout.type = PatternLayout appender.0.layout.pattern = ${pattern} # 全量日志文件Appender appender.1.type = File appender.1.name = ALL_LOG_FILE appender.1.fileName = logs/all.log appender.1.layout.type = PatternLayout appender.1.layout.pattern = ${pattern} # -------------------------- 分级别专属Appender(添加过滤规则) -------------------------- # OFF级别(特殊,OFF是关闭所有日志,文件会一直为空) appender.2.type = File appender.2.name = OFF_LOG_FILE appender.2.fileName = logs/off.log appender.2.layout.type = PatternLayout appender.2.layout.pattern = ${pattern} # FATAL级别专属Appender appender.3.type = File appender.3.name = FATAL_LOG_FILE appender.3.fileName = logs/fatal.log appender.3.layout.type = PatternLayout appender.3.layout.pattern = ${pattern} # 只接受FATAL级别日志,拒绝其他所有 appender.3.filter.0.type = LevelMatchFilter appender.3.filter.0.level = FATAL appender.3.filter.0.onMatch = ACCEPT appender.3.filter.1.type = DenyAllFilter # ERROR级别专属Appender appender.4.type = File appender.4.name = ERROR_LOG_FILE appender.4.fileName = logs/error.log appender.4.layout.type = PatternLayout appender.4.layout.pattern = ${pattern} appender.4.filter.0.type = LevelMatchFilter appender.4.filter.0.level = ERROR appender.4.filter.0.onMatch = ACCEPT appender.4.filter.1.type = DenyAllFilter # WARN级别专属Appender appender.5.type = File appender.5.name = WARN_LOG_FILE appender.5.fileName = logs/warn.log appender.5.layout.type = PatternLayout appender.5.layout.pattern = ${pattern} appender.5.filter.0.type = LevelMatchFilter appender.5.filter.0.level = WARN appender.5.filter.0.onMatch = ACCEPT appender.5.filter.1.type = DenyAllFilter # INFO级别专属Appender appender.6.type = File appender.6.name = INFO_LOG_FILE appender.6.fileName = logs/info.log appender.6.layout.type = PatternLayout appender.6.layout.pattern = ${pattern} appender.6.filter.0.type = LevelMatchFilter appender.6.filter.0.level = INFO appender.6.filter.0.onMatch = ACCEPT appender.6.filter.1.type = DenyAllFilter # DEBUG级别专属Appender appender.7.type = File appender.7.name = DEBUG_LOG_FILE appender.7.fileName = logs/debug.log appender.7.layout.type = PatternLayout appender.7.layout.pattern = ${pattern} appender.7.filter.0.type = LevelMatchFilter appender.7.filter.0.level = DEBUG appender.7.filter.0.onMatch = ACCEPT appender.7.filter.1.type = DenyAllFilter # TRACE级别专属Appender appender.8.type = File appender.8.name = TRACE_LOG_FILE appender.8.fileName = logs/trace.log appender.8.layout.type = PatternLayout appender.8.layout.pattern = ${pattern} appender.8.filter.0.type = LevelMatchFilter appender.8.filter.0.level = TRACE appender.8.filter.0.onMatch = ACCEPT appender.8.filter.1.type = DenyAllFilter # -------------------------- 分级别Logger配置(禁止继承RootLogger) -------------------------- logger.0.name = de.hoelzer.all.log.console logger.0.level = ALL logger.0.appenderRef.0.ref = ALL_LOG_CONSOLE logger.0.additivity = false # 禁止继承RootLogger的输出规则,避免重复日志 logger.1.name = de.hoelzer.all.log.file logger.1.level = ALL logger.1.appenderRef.0.ref = ALL_LOG_FILE logger.1.additivity = false logger.2.name = de.hoelzer.off.log.file logger.2.level = OFF logger.2.appenderRef.0.ref = OFF_LOG_FILE logger.2.additivity = false logger.3.name = de.hoelzer.fatal.log.file logger.3.level = FATAL logger.3.appenderRef.0.ref = FATAL_LOG_FILE logger.3.additivity = false logger.4.name = de.hoelzer.error.log.file logger.4.level = ERROR logger.4.appenderRef.0.ref = ERROR_LOG_FILE logger.4.additivity = false logger.5.name = de.hoelzer.warn.log.file logger.5.level = WARN logger.5.appenderRef.0.ref = WARN_LOG_FILE logger.5.additivity = false logger.6.name = de.hoelzer.info.log.file logger.6.level = INFO logger.6.appenderRef.0.ref = INFO_LOG_FILE logger.6.additivity = false logger.7.name = de.hoelzer.debug.log.file logger.7.level = DEBUG logger.7.appenderRef.0.ref = DEBUG_LOG_FILE logger.7.additivity = false logger.8.name = de.hoelzer.trace.log.file logger.8.level = TRACE logger.8.appenderRef.0.ref = TRACE_LOG_FILE logger.8.additivity = false # -------------------------- RootLogger配置(精简为只输出全量日志) -------------------------- rootLogger.level = ALL rootLogger.appenderRef.0.ref = ALL_LOG_CONSOLE rootLogger.appenderRef.1.ref = ALL_LOG_FILE
关键调整点说明
- 给分级别Appender加
LevelMatchFilter:这个过滤器的作用是只接受指定级别的日志,后续的DenyAllFilter会拒绝所有其他级别,彻底确保每个文件只存对应级别的日志。 - 给每个Logger加
additivity = false:禁止Logger继承RootLogger的Appender输出规则,避免同一条日志被重复输出到多个文件。 - 精简RootLogger的Appender引用:RootLogger只负责输出全量日志到控制台和all.log,不再插手分级别文件的输出,从根源上避免混乱。
这样改完之后,你再启动程序打日志,trace.log就只会有TRACE级别的内容,debug.log只会有DEBUG级别的,INFO及以上的日志就不会混进去了,完全符合你的预期!




