当前位置: 首页 > news >正文

项目日志框架与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

http://www.xdnf.cn/news/1296829.html

相关文章:

  • MFC的使用——使用ChartCtrl绘制曲线
  • DataHub IoT Gateway:工业现场设备与云端平台安全互联的高效解决方案
  • 使用HalconDotNet实现异步多相机采集与实时处理
  • 零信任架构(Zero Trust Architecture, ZTA)(通过动态验证和最小权限控制,实现对所有访问请求的严格授权和持续监控)
  • Kafka消费者组
  • OpenCV阈值处理详解
  • Docker pull拉取镜像命令的入门教程
  • K8s学习----Namespace:资源隔离与环境管理的核心机制
  • Rabbitmq+STS+discovery_k8s +localpv部署排坑详解
  • 希尔排序专栏
  • C++ 仿RabbitMQ实现消息队列项目
  • Trae x Figma MCP一键将设计稿转化为精美网页
  • 通信算法之313:FPGA中实现滑动相关消耗DSP资源及7045/7035的乘法器资源
  • Mysql基本使用语句(一)
  • 读《精益数据分析》:移情(Empathy)—— 验证真实需求,避免伪需求陷阱
  • OpenLayers与Vue.js结合实现前端地图应用
  • 51单片机-驱动LED模块教程
  • 机器视觉之图像处理篇
  • 相较于传统AR作战环境虚拟仿真系统,其优势体现在哪些方面?
  • Flutter 顶部导航标签组件Tab + TabBar + TabController
  • 读From GPT-2 to gpt-oss: Analyzing the Architectural Advances
  • 线上故障定位:从报警到根因的实战指南
  • 计算机如何进行“卷积”操作:从图像到矩阵的奥秘
  • 设计模式笔记_行为型_责任链模式
  • [机器学习]08-基于逻辑回归模型的鸢尾花数据集分类
  • 高分辨率PDF压缩技巧:保留可读性的最小体积方案
  • 通过网页调用身份证阅读器http websocket方法-华视电子————仙盟创梦IDE
  • 【数据结构初阶】--排序(一):直接插入排序,希尔排序
  • MySQL的索引(索引的创建和设计原则):
  • 并发编程 - 读写锁(ReentrantReadWriteLock)的探究