You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

关键调整点说明

  1. 给分级别Appender加LevelMatchFilter:这个过滤器的作用是只接受指定级别的日志,后续的DenyAllFilter会拒绝所有其他级别,彻底确保每个文件只存对应级别的日志。
  2. 给每个Logger加additivity = false:禁止Logger继承RootLogger的Appender输出规则,避免同一条日志被重复输出到多个文件。
  3. 精简RootLogger的Appender引用:RootLogger只负责输出全量日志到控制台和all.log,不再插手分级别文件的输出,从根源上避免混乱。

这样改完之后,你再启动程序打日志,trace.log就只会有TRACE级别的内容,debug.log只会有DEBUG级别的,INFO及以上的日志就不会混进去了,完全符合你的预期!

火山引擎 最新活动