如何在Log4j2配置中避免日志重复写入?
解决Log4j2日志重复写入问题
问题根源分析
你的配置存在两个核心问题导致日志重复:
- Root Logger重复关联Appender:Root节点同时引用了
routingAppender、allFileAppender、errorFileAppender和consoleAppender,同一日志会被多个Appender分别写入对应文件。 - Routing Appender结构违规:将
allFileAppender、errorFileAppender、consoleAppender嵌套在routingAppender内部不符合Log4j2规范,Routing Appender仅允许Routes和Script作为子元素,这些嵌套的Appender不会被路由逻辑使用,反而会因为Root的直接引用重复输出。
修正后的配置方案
根据常见的日志分层需求(动态业务日志、全量日志、错误日志、控制台输出),调整配置如下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <!-- 默认业务日志Appender --> <RollingFile name="fileAppender" fileName="log/application.log" filePattern="log/application.log.%i"> <PatternLayout> <pattern>%p{length=1} %d{yyMMdd HH:mm:ss.SSS} [%t] %c{1} %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="${LOG_FILE_SIZE}"/> </Policies> <DefaultRolloverStrategy max="${BACKUP_INDEX}"/> <!-- 过滤ERROR级别,避免与错误日志文件重复 --> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="ACCEPT"/> </RollingFile> <!-- 动态业务日志Appender(根据MDC路由) --> <Routing name="routingAppender"> <Routes pattern="$${mdcContext}"> <Route> <RollingFile name="dynamicFileAppender" fileName="log/application.${mdcContext}.log" filePattern="log/application.${mdcContext}.log.%i"> <PatternLayout> <pattern>%p{length=1} %d{yyMMdd HH:mm:ss.SSS} [%t] %c{1} %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="${LOG_FILE_SIZE}"/> </Policies> <DefaultRolloverStrategy max="${BACKUP_INDEX}"/> <!-- 过滤ERROR级别 --> <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="ACCEPT"/> </RollingFile> </Route> <Route ref="fileAppender" key="$${mdcContext}"/> </Routes> </Routing> <!-- 全量日志Appender(包含所有级别) --> <RollingFile name="allFileAppender" fileName="log/application.all.log" filePattern="log/application.all.log.%i"> <PatternLayout> <pattern>%p{length=1} %d{yyMMdd HH:mm:ss.SSS} [%t] %c{1} - %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="${LOG_FILE_SIZE}"/> </Policies> <DefaultRolloverStrategy max="${BACKUP_INDEX}"/> </RollingFile> <!-- 错误日志Appender(仅ERROR级别) --> <RollingFile name="errorFileAppender" fileName="log/application.error.log" filePattern="log/application.error.log.%i"> <PatternLayout> <pattern>%p{length=1} %d{yyMMdd HH:mm:ss.SSS} [%t] %c{1} - %m%n</pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="${LOG_FILE_SIZE}"/> </Policies> <DefaultRolloverStrategy max="${BACKUP_INDEX}"/> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> </RollingFile> <!-- 控制台输出(仅ERROR级别) --> <Console name="consoleAppender" target="SYSTEM_OUT"> <PatternLayout pattern="%p{length=1} %d{yyMMdd HH:mm:ss.SSS} [%t] %c{1} %m%n"/> <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/> </Console> </Appenders> <Loggers> <Logger name="org.apache.commons" level="INFO"/> <Logger name="org.quartz.simpl.SimpleThreadPool" level="INFO"/> <Logger name="org.quartz.core.QuartzSchedulerThread" level="INFO"/> <Logger name="org.quartz.core.JobRunShell" level="ERROR"/> <Logger name="com.example" level="ERROR"/> <Logger name="org.apache.activemq.artemis.core.server" level="INFO"/> <!-- <Logger name="example.scheduler" level="debug"> <AppenderRef ref="routingAppender"/> </Logger> --> <Root level="${LOGGING_LEVEL}"> <AppenderRef ref="routingAppender"/> <AppenderRef ref="allFileAppender"/> <AppenderRef ref="errorFileAppender"/> <AppenderRef ref="consoleAppender"/> </Root> </Loggers> </Configuration>
关键调整说明
- 修正Appender结构:将
allFileAppender、errorFileAppender、consoleAppender移至顶级<Appenders>标签下,符合Log4j2配置规范。 - 添加级别过滤:
- 给
fileAppender和dynamicFileAppender添加ThresholdFilter,拒绝ERROR级别日志,避免业务日志文件混入错误日志。 - 给
errorFileAppender和consoleAppender添加ThresholdFilter,仅接受ERROR级别日志,确保只输出错误内容。
- 给
- 保留全量日志:
allFileAppender不添加过滤,收集所有级别的日志,满足归档需求。
如果你的需求是完全禁止同一日志出现在多个文件中(比如不需要全量日志),可以直接移除Root节点中的<AppenderRef ref="allFileAppender"/>,仅保留业务路由、错误日志和控制台输出。
内容的提问来源于stack exchange,提问作者Deendayal Kumawat
相关产品推荐
相关产品推荐

