项目日志框架与jar中日志框架冲突 解决
背景
项目用的日志框架是Log4j2,依赖如下:
<dependency> <!-- 引入log4j2依赖 --><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId><version>${boot.version}</version></dependency>
第三方日志框架
依赖
<dependencies><dependency><groupId>${project.groupId}</groupId><artifactId>ctg-mq-common</artifactId><exclusions><exclusion><groupId>io.netty</groupId><artifactId>netty-tcnative</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><scope>test</scope></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId></dependency></dependencies>
创建日志方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.apache.rocketmq.client.log;import java.lang.reflect.Method;
import java.net.URL;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ClientLogger {public static final String CLIENT_LOG_ROOT = "rocketmq.client.logRoot";public static final String CLIENT_LOG_MAXINDEX = "rocketmq.client.logFileMaxIndex";public static final String CLIENT_LOG_LEVEL = "rocketmq.client.logLevel";private static Logger log;private static Logger createLogger(String loggerName) {String logConfigFilePath = System.getProperty("rocketmq.client.log.configFile", System.getenv("ROCKETMQ_CLIENT_LOG_CONFIGFILE"));Boolean isloadconfig = Boolean.parseBoolean(System.getProperty("rocketmq.client.log.loadconfig", "true"));String log4JResourceFile = System.getProperty("rocketmq.client.log4j.resource.fileName", "log4j_rocketmq_client.xml");String logbackResourceFile = System.getProperty("rocketmq.client.logback.resource.fileName", "logback_rocketmq_client.xml");String log4J2ResourceFile = System.getProperty("rocketmq.client.log4j2.resource.fileName", "log4j2_rocketmq_client.xml");String clientLogRoot = System.getProperty("rocketmq.client.logRoot", System.getProperty("user.home") + "/logs/rocketmqlogs");System.setProperty("client.logRoot", clientLogRoot);String clientLogLevel = System.getProperty("rocketmq.client.logLevel", "INFO");System.setProperty("client.logLevel", clientLogLevel);String clientLogMaxIndex = System.getProperty("rocketmq.client.logFileMaxIndex", "10");System.setProperty("client.logFileMaxIndex", clientLogMaxIndex);if (isloadconfig) {try {ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();Class classType = iLoggerFactory.getClass();if (classType.getName().equals("org.slf4j.impl.Log4jLoggerFactory")) {Class<?> domconfigurator = Class.forName("org.apache.log4j.xml.DOMConfigurator");Object domconfiguratorobj = domconfigurator.newInstance();if (null == logConfigFilePath) {Method configure = domconfiguratorobj.getClass().getMethod("configure", URL.class);URL url = ClientLogger.class.getClassLoader().getResource(log4JResourceFile);configure.invoke(domconfiguratorobj, url);} else {Method configure = domconfiguratorobj.getClass().getMethod("configure", String.class);configure.invoke(domconfiguratorobj, logConfigFilePath);}} else if (classType.getName().equals("ch.qos.logback.classic.LoggerContext")) {Class<?> context = Class.forName("ch.qos.logback.core.Context");Class<?> joranConfigurator = Class.forName("ch.qos.logback.classic.joran.JoranConfigurator");Object joranConfiguratoroObj = joranConfigurator.newInstance();Method setContext = joranConfiguratoroObj.getClass().getMethod("setContext", context);setContext.invoke(joranConfiguratoroObj, iLoggerFactory);if (null == logConfigFilePath) {URL url = ClientLogger.class.getClassLoader().getResource(logbackResourceFile);Method doConfigure = joranConfiguratoroObj.getClass().getMethod("doConfigure", URL.class);doConfigure.invoke(joranConfiguratoroObj, url);} else {Method doConfigure = joranConfiguratoroObj.getClass().getMethod("doConfigure", String.class);doConfigure.invoke(joranConfiguratoroObj, logConfigFilePath);}} else if (classType.getName().equals("org.apache.logging.slf4j.Log4jLoggerFactory")) {Class<?> joranConfigurator = Class.forName("org.apache.logging.log4j.core.config.Configurator");Method initialize = joranConfigurator.getDeclaredMethod("initialize", String.class, String.class);if (null == logConfigFilePath) {initialize.invoke(joranConfigurator, "log4j2", log4J2ResourceFile);} else {initialize.invoke(joranConfigurator, "log4j2", logConfigFilePath);}}} catch (Exception e) {System.err.println(e);}}return LoggerFactory.getLogger("RocketmqClient");}public static Logger getLog() {if (log == null) {log = createLogger("RocketmqClient");return log;} else {return log;}}public static void setLog(Logger log) {ClientLogger.log = log;}
}
在不做处理的情况下,调用第三方jar中方法后会提示
2025-08-14 15:31:02,506 main WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender
然后只能输出error日志了
原因
问题是典型的 日志框架冲突 和 日志配置未正确加载 导致的。根据你的描述,问题发生在调用第三方 JAR 中的类时,日志从正常输出 INFO
级别突然只能输出 ERROR
级别,并出现如下警告:
WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender
这说明 Log4j2 没有找到有效的配置文件,使用了默认的错误级别根日志器(Root Logger)。
解决方法
问题分析
1. 第三方 JAR 中的日志初始化逻辑
你贴出的 createLogger()
方法是 RocketMQ 客户端或类似中间件的典型日志初始化方式。它通过反射动态判断当前使用的日志实现(Log4j、Logback、Log4j2),然后尝试加载对应的配置文件(如 log4j2_rocketmq_client.xml
)。
关键点是:
} else if (classType.getName().equals("org.apache.logging.slf4j.Log4jLoggerFactory")) {Class<?> joranConfigurator = Class.forName("org.apache.logging.log4j.core.config.Configurator");Method initialize = joranConfigurator.getDeclaredMethod("initialize", String.class, String.class);if (null == logConfigFilePath) {initialize.invoke(joranConfigurator, "log4j2", log4J2ResourceFile); // ← 默认加载 log4j2_rocketmq_client.xml} else {initialize.invoke(joranConfigurator, "log4j2", logConfigFilePath);}
}
这段代码会 强制使用 Configurator.initialize()
重新初始化 Log4j2 的配置,而这个方法会 覆盖当前已有的 Log4j2 配置!
2. 为什么只输出 ERROR 日志?
因为第三方 JAR 尝试加载的 log4j2_rocketmq_client.xml
文件在你的项目 classpath 中 不存在,导致 Log4j2 初始化失败,进入“默认模式”——只创建一个 ERROR
级别的 Root Logger 并绑定 Console Appender。
这就是警告信息的来源:
WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender
方案一:提供第三方所需的 Log4j2 配置文件(推荐)
推荐
System.setProperty("rocketmq.client.log.loadconfig", "false");
-Drocketmq.client.log.loadconfig=false