由jar包冲突导致的logback日志不输出

2023-11-01

一、前言

最近升级一个老项目,发面日志没有按照预期的生成。

1、resource下面有logback配置但没有生成日志

检查resource目录下,发现有logback.xml配置,但部署在服务器的项目没有按配置生成日志。于是启动本地tomcat发现日志按logback配置生成了。
检查了下logback.xml配置内容,发现并没有什么不同。看了下在控台输出的日志,发现下面这段
在这里插入图片描述
SLF4J: Class path contains multiple SLF4J bindings.
slf4j 包含多个slf4j的绑定,我们知道,slf4j是一个门面 ,市面上有很多日志框架比如:log4j ,common log,logback等。
目前我们用的是logback。
而这里告诉我们:SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory],实际绑定的是Log4jLoggerFactory
并且日志也明确说明,有2个jar提供了StaticLoggerBinde r.clas,所以这里需要把所有引用log4j的地方去掉,

2、去掉Log4j依赖引用

其实控台打印的日志中还有一行提示:SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
这里举了个例说明如何排除log4j冲突jar,如下:
在这里插入图片描述

这里直接引的log4j的jar很好去掉,间接引的 需要在用Dependency Analyzer中搜索,发现zookeep的jar中引用了Log4j,于是添加如下:

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>${zookeeper-version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

重启项目 解决。

3、java是如何加载logback

我们都知道,当我们需要引入logback时,是不是需添加任何配置 来引入logback.xml文件的,只需要将logback.xml配置文件定义到resources目录即可,那么框架会自动加载这个日志配置文件,并按照配置帮我自己生成日志到指定的目录下,那么它是如何自动加载的。
很显然第一个想到就是通过spi。
在说明如何加载的一个前提是,你需要知道sl4j、log4j、logback之间的关系。
可以看这篇 SLF4J和Logback和Log4j和Logging的区别与联系

这里我还是贴一张图来说明一下:
在这里插入图片描述
slf4j是一个门面,而logback、log4j都是这个门面的实现。
所以logback肯定是在sl4j.jar中加载的。

3.1、回顾下我们获取日志对象是如何获取的

//通过LoggerFactory获取一个logger对象
final static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

//通过LoggerFactory获取一个logger对象,那么我们看下这个方法如下:
在这里插入图片描述
它果然是在slf4j这个门面中定义的。

public static Logger getLogger(Class<?> clazz) {
   //看下是如何获取logger 的
   Logger logger = getLogger(clazz.getName());
   if (DETECT_LOGGER_NAME_MISMATCH) {
       Class<?> autoComputedCallingClass = Util.getCallingClass();
       if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
           Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
                           autoComputedCallingClass.getName()));
           Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
       }
   }
   return logger;
}

getLogger

public static Logger getLogger(String name) {
    //看下这个方法
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
}
public static ILoggerFactory getILoggerFactory() {
     if (INITIALIZATION_STATE == UNINITIALIZED) {
         synchronized (LoggerFactory.class) {
             if (INITIALIZATION_STATE == UNINITIALIZED) {
                 INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                 //看这个方法
                 performInitialization();
             }
         }
     }
     ......
}     

查看performInitialization 的bind方法

  private final static void performInitialization() {
     //绑定
     bind();
     if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
         versionSanityCheck();
     }
 }
private final static void bind() {
    ....
    staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
    .....
}
 private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

static Set<URL> findPossibleStaticLoggerBinderPathSet() {
     // use Set instead of list in order to deal with bug #138
     // LinkedHashSet appropriate here because it preserves insertion order
     // during iteration
     Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
     try {
         ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
         Enumeration<URL> paths;
         if (loggerFactoryClassLoader == null) {
         //加载org/slf4j/impl/StaticLoggerBinder.class这个类
             paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
         } else {
             paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
         }
         while (paths.hasMoreElements()) {
             URL path = paths.nextElement();
             staticLoggerBinderPathSet.add(path);
         }
     } catch (IOException ioe) {
         Util.report("Error getting resources from path", ioe);
     }
     return staticLoggerBinderPathSet;
 }

上面方法会加 //加载org/slf4j/impl/StaticLoggerBinder.class这个类这个类,那么我们先看下slf4j下有没有这个类:
在这里插入图片描述
这个jar下没有这个路径,那么肯定是在slf4j-logback.jar,slf4j-log4j.jar这样的jar包下实现的。
搜索logback相关jar,发现在这个jar下有这个路径类
在这里插入图片描述
然后继续,看bind方法后面
在这里插入图片描述
如果你的项目中只有logback-classic这一个Jar,没有其它日志框架,那么直接点到这个方法中就到logback方法中,如下:
在这里插入图片描述
这个类中静态方法就会执行
在这里插入图片描述
看下init方法
在这里插入图片描述
autoConfig()中findURLOfDefaultConfigurationFile方法
在这里插入图片描述
再继续看autoConfig()方法
在这里插入图片描述
后面就不在细说明,可以直接到源码里面看看。
这里整个logback自动注入的过程就完结了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

由jar包冲突导致的logback日志不输出 的相关文章

随机推荐

  • 正则表达式之ip地址匹配(详细讲解)

    正则表达式之ip地址匹配 一 正则匹配基本知识及概念 二 ip地址匹配 一 正则匹配基本知识及概念 在练习之前 需要大家知道一些基本知识 如果有一定基础的可以跳过该步骤 直接往下看 正则表达式 字符类 abc 代表a或者b 或者c字符中的一
  • lambda函数

    lambda函数也叫匿名函数 就是没有函数名的函数 lambda表达式基于数学中的 演算得名 直接对应于其中的lambda抽象 lambda函数的语法只包含一个语句 lambda arg1 arg2 argn expression 冒号前面
  • 设计模式(十九) 备忘录模式

    备忘录模式是一种行为型模式 作用是将对象的内部状态保存下来 在必要的时候恢复 备忘录模式可以用于游戏存档恢复 文件的历史记录等场合 下面是一个简单的代码例子 首先是文档管理器 用于保存文档的状态 public class DocumentM
  • 【Eclipse】Maven安装配置&Eclipse配置Maven插件

    文章目录 前言 一 下载安装Maven 二 配置Maven环境变量 三 修改Maven仓库配置 四 Eclipse配置 maven
  • JS提取链接参数

    假如要提取当前网络链接上面的参数 那么请看下去 比如要提取 var url http www baidu com x 10 y 20 c 30 d 40 中的 xycd的值 那么
  • 【已解决】SpringBoot 后端开发中console中中文乱码问题,以及其他解决方法。

    项目场景 在IDEA中 使用Maven构建SpringBoot Web后端项目 黑马程序员中的javaWeb 2023最新课程中的案例 有同样问题的同学欢迎一起讨论学习 问题描述 前端网页请求发出后 后端成功响应 但是在控制台中 中文数据会
  • C标准库文件&常用函数

    编号 头文件 C标准版本 介绍 1
  • MIPI DPHY接口的若干种实现方案概述

    一 MIPI DPHY接口简介 MIPI DPHY是MIPI的一种物理层 其协议层有CSI和DSI两种 其中CSI主要用于图像接入 如图像传感器Sensor DSI主要用于图像输出 如手机屏幕等 有关MIPI DPHY及CSI和DSI的技术
  • 涡阳2021年高考成绩查询,2021年涡阳县高考状元名单资料,今年涡阳县高考状元多少分...

    高考状元一直都备受大家的关注 不管对于学校和还是当地教育系统 都是一件荣誉的事情 高考状元历来都诞生于艳羡的目光中 大家为他们的高分叫好 羡慕他们可以一步踏入国内知名学府 本文高考升学网为大家介绍历年涡阳县高考状元的相关资料和考分情况 看看
  • 互斥锁、读写锁、自旋锁、条件变量的特点总结

    读写锁特点 1 多个读者可以同时进行读 2 写者必须互斥 只允许一个写者写 也不能读者写者同时进行 3 写者优先于读者 一旦有写者 则后续读者必须等待 唤醒时优先考虑写者 互斥锁特点 一次只能一个线程拥有互斥锁 其他线程只有等待 互斥锁是在
  • 新闻管理系统

    1 项目介绍 新闻管理系统拥有两个角色 分别为用户和管理员 具体功能如下 2 项目技术 后端框架 Jfinal mvc 前端框架 Freemarker html css JavaScript JQuery 3 开发环境 JAVA版本 JDK
  • css transparent张鑫旭,【灵感杂谈】张鑫旭和他的《CSS世界》

    原标题 灵感杂谈 张鑫旭和他的 CSS世界 说到本书的作者 前端圈里没见过他的人有很多 但没读过他文章的人很少 他就是很多前端同行眼中的 张老师 张大神 张鑫旭 以下简称 张 前一段时间 去参加 前端体验大会 有一位张的同事作为分享嘉宾 当
  • 清风数学建模学习笔记——熵权法(客观赋权法)

    熵权法 熵权法是一种客观赋权方法 客观 数据本身就可以告诉我们权重 依据的原理 指标的变异程度越小 所反映的信息量也越少 其对应的权值也应该越低 本文借鉴了数学建模清风老师的课件与思路 如果大家发现文章中有不正确的地方 欢迎大家在评论区留言
  • Vue.js用cdn方式引入

    Vue js用cdn方式引入 前言 注意本次用cdn形式引入js学习 有node js的玩家可以用node js CDN下载地址 https vuejs org js vue min js以及Node js Vue系列 windows下np
  • 解决asterisk sip错误提示Not Acceptable Here(488)或Not Found(404)

    安装好asterisk后对接到VOS3000使用 可发现VOS死活送不通asterisk 于是回头检查asterisk系统是否安装正确以及是否正常工作 经过反复检查 都没有发现问题 可VOS上面话单显示 开始一直显示488错误 于是我看了下
  • policy gradient详解(附代码)

    1 引言 policy gradient是强化学习中一种基于概率策略的方法 智能体通过与环境的交互获得特定时刻的状态信息 并直接给出下一步要采取各种动作的概率 然后根据该状态动作的策略分布采取下一步的行动 所以每种动作都有可能被选中 只是选
  • 计算 属性

    一 定义 计算属性就是当其依赖属性的值发生变化时 这个属性的值会自动更新 预支相关的DOM部分也会同步自动更新 有缓存 二 用法 1 基础用法 computed getN return this n 1 2 传递参数 返回一个函数 h1 t
  • mmdetection源码阅读

    阅读从tools train py开始 功能模块 Register类 位置 utils registry py 用于注册起到相同作用的 例如coco voc数据类 模型类 数据处理流程类 类别 具体功能是这样的 Register的 init
  • 很不起眼的6个bug,90%的程序员就算写了10年代码也肯定都踩过!

    文章来源 https juejin cn post 7120570066856312839 前言 作为Java程序员的你 不知道有没有踩过一些基础知识的坑 有时候 某个bug查了半天 最后发现竟然是一个低级错误 有时候 某些代码 这一批数据
  • 由jar包冲突导致的logback日志不输出

    文章目录 一 前言 1 resource下面有logback配置但没有生成日志 2 去掉Log4j依赖引用 3 java是如何加载logback 3 1 回顾下我们获取日志对象是如何获取的 一 前言 最近升级一个老项目 发面日志没有按照预期