java 日志重复记录通常由 appender 继承、logger 级别配置错误或多线程并发写入引起。排查时先检查 logger 的 additivity 属性是否被错误设为 true,再确认同一 logger 是否被多次绑定到不同的 appender,最后通过线程栈分析排除并发导致的日志交错或重复打印。

如何检查 Logger 的 additivity 属性
当 additivity 为 true 时,子 Logger 会向父 Logger 的 Appender 传递日志事件,导致日志在子 Appender 和父 Appender 中各打印一次。要解决此问题,需在配置文件中将 additivity 显式设置为 false,从而切断向上传递的路径。

<?xml version="1.0" encoding="UTF-8"?><configuration status="WARN"><appenders><console name="Console" target="SYSTEM_OUT"><patternlayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"></patternlayout></console></appenders><loggers><!-- 设置 additivity=false 防止日志向上传递给 Root --><logger name="com.example.service" level="info" additivity="false"><appenderref ref="Console"></appenderref></logger><root level="error"><appenderref ref="Console"></appenderref></root></loggers></configuration>
上述配置中,com.example.service 包下的日志只会输出到 Console,而不会再次触发 Root Logger 的配置。如果未设置 additivity="false",且 Root 也引用了 Console,则同一条日志会被打印两次。
如何排查多个 Appender 绑定同一 Logger
如果同一个 Logger 被显式绑定了多个 Appender,或者通过通配符匹配到了多个 Appender,也会导致日志重复。需要检查配置文件或代码中是否存在对同一 Logger 的多重 AppenderRef 引用,并确保每个 Appender 都有唯一的名称和输出目标。
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LogTest {
private static final Logger logger = LogManager.getLogger(LogTest.class);
public static void main(String[] args) {
// 模拟业务逻辑
logger.info("This is a test message");
}
}
运行该程序后,观察控制台输出。如果看到两条相同的 "This is a test message",请检查 log4j2.xml 中 com.example 相关的 Logger 配置,确保没有重复的 AppenderRef。例如,避免同时出现 和 且两者都指向同一输出流的情况。
基于多线程环境下日志重复的具体问题
在多线程环境中,日志重复可能表现为日志行交错或内容看似重复。这通常是由于多个线程同时调用 logger.info(),而日志框架的输出缓冲区未正确同步所致。虽然现代日志框架如 Log4j2 和 SLF4J 默认是线程安全的,但如果自定义了 Appender 或未使用异步 Appender,仍可能出现重复或丢失。
为解决此问题,建议使用异步 Appender(如 AsyncAppender)来缓冲日志事件,减少 I/O 竞争。同时,确保日志格式中包含线程信息(如 %t),以便在排查时区分不同线程的日志来源。如果问题依旧,检查是否有多个 Logger 实例指向同一底层 Appender,这在某些框架配置中可能导致重复记录。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










