关于报错 SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“ 的可能原因

news2024/11/26 6:00:09

1. 絮絮叨叨

  • 学习或工作中,如果需要从头建立日志打印体系,笔者通常直接照抄之前的博客:《Java maven工程配置slf4j》,直接粘贴、复制相关依赖
  • 除了上述博客提到的slf4j-api、logback-classic,也看到过slf4j-simple、log4j、log4j2等,但实际不清楚它们之间的关系
  • 最近的工作,促使笔者简单恶补了日志框架
  • 关于日志框架的发展,从Log4j → \rightarrow JUL(Java Util Logging) → \rightarrow Apache Cmmons Logging → \rightarrow SLF4J:Java日志框架介绍和 Slf4j 使用
  • 关于SLF4J(Simple logging Facade for Java)
    • SLF4J是一个日志门面,而非具体的日志框架。它提供了统一的日志记录接口,可以对接不同的日志系统
    • 只要按照其提供方式记录日志,最终日志的格式、级别、输出方式等都由绑定的具体日志系统来实现和决定
    • 也就说,想要使用打印日志,需要绑定具体的日志框架,例如:SLF4J + Logback的常见组合
    • 参考文档:Java 学习笔记 - 日志体系:SLF4J 是啥?与各日志框架啥关系?、Java日志框架:slf4j作用及其实现原理

2. 关于报错 SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder” 的可能原因

  • 在使用SLF4J时,可能会遇到如下报错
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    
  • 最常见的原因:新手不会使用SLF4J,只引入了SLF4J,没有引入具体的日志框架
  • 但笔者遇到的原因则比较少见:SLF4J + Logback组合,二者的version不匹配导致

2.1 未引入具体的日志框架

  • 自建一个maven项目,引入SLF4J依赖

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    
  • 在代码中打印日志

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class LoggerTest {
        private static final Logger logger = LoggerFactory.getLogger(LoggerTest.class);
    
        public static void main(String[] args) {
            logger.info("Hello world!");
        }
    }
    
  • 由于未引入具体的日志框架,将导致程序运行报错
    在这里插入图片描述

  • 从报错信息给出的链接,将得到该报错的可能原因

    • 该报错信息来自slf4j-api 1.7.x或更早版本slf4j-api 2.x 或更高版本不再使用StaticLoggerBinder,而是使用 ServiceLoader 机制
    • 错误原因:classpath中没有发现合适的SLF4J binding,也就是没有具体日志框架,引入slf4j-nop.jar slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jarlogback-classic.jar中的任一一种就可以解决问题
  • 笔者选择使用logback作为日志实现,添加如下依赖便可以解决问题

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    
  • 最终成功打印日志在这里插入图片描述

2.2 SLF4J + Logback组合,二者的version不匹配

  • 笔者最近工作的项目,使用的是slf4j-api 2.0.7 + logback 1.4.5版本的日志组合
  • 但由于需要上报指标,引入第三方依赖metrics,从而引入了slf4j-api 1.7.21
    项目的commons模块 
    	--> 第三方metrics依赖
    	--> httpasyncclient-shade-1.0.10.jar
    	--> slf4j-api-1.7.21.jar
    
  • 最终,服务启动时加载到了隐形的slf4j-api-1.7.21.jar。与该版本适配的是logback 1.2.x版本,而非服务中已有的logback 1.4.5
  • 这是一个多节点的分布式服务,笔者查看日志时发现:有的节点无任何日志输出,服务启动日志报错:SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
  • 因此,笔者怀疑:metrics依赖导致服务日志体系被破坏

2.2.1 曲折的排查过程

  • 由于笔者一开始没有仔细阅读官方描述,更没有想过存在隐形的低版本slf4j-api,各种调整依赖引入,折腾了1天多皆无果
  • 最终,静下心来、重整旗鼓后,从stackoverflow得到了启发:SLF4J with logback still prompt failed to load class “org.slf4j.impl.StaticLoggerBinder”,怀疑是版本不匹配
  • 但笔者多次检查过服务的classpath,确定提供的均是slf4j-api 2.0.7 + logback 1.4.5的jar包,没有其他版本的slf4j-api或logback
  • 最终,通过arthas sc命令查看服务中加载slf4j依赖,发现无法打印日志的节点,加载的slf4j来自httpasyncclient-shade-1.0.10.jar,而非预期的、classpath中的slf4j-api-2.0.7.jar
    • 使用的arthas命令如下:
      # 查看加载的slf4j相关类
      sc org.slf4j.*
      
      # 查看Logger类的详细加载信息
      sc -d org.slf4j.Logger
      
    • 对于成功打印日志的节点,可以看出加载的slf4j是符合预期在这里插入图片描述
    • 对于无法打印日志的节点,加载的slf4j则来自第三方依赖
      在这里插入图片描述
  • 通过验证slf4j 1.7.21 + logback 1.4.5组合,以及咨询依赖提供方,发现slf4j确实是1.7.x版本,且与logback 1.4.5版本组合会触发报错:SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    在这里插入图片描述
  • 与依赖提供方确认后,将httpasyncclient-shade-1.0.10.jar排除掉,再重新打包、部署服务,发现日志打印回复正常

2.2.2 SLF4J + Logback的版本适配问题

  • 从之前SLF4J官网对错误(SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".)的解释推测:
    • slf4j-api 1.7.x及更低版本,使用StaticLoggerBinder,对应的logback 1.2.x或更低版本?
    • slf4j-api 2.0.x及更高版本,使用 ServiceLoader 机制,对应的logback 1.3.x或更高版本
  • 博客Java Logging Part 2: Logging and Package Exclusion with SLF4J + Logback的介绍更加详细
    在这里插入图片描述
  • 同时,从Logback的官网看:logback 1.3.x和1.4.x要求slf4j-api 2.0.x版本
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2092642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

区域生长算法详解与Python实现

图像分割是计算机视觉中一个重要的任务&#xff0c;区域生长算法是其中的一种常见方法。本文将详细介绍区域生长算法的原理&#xff0c;并通过Python代码实现&#xff0c;带你一步步理解它的实际应用。 1. 区域生长算法简介 区域生长算法是一种基于像素相似性进行图像分割的方…

2025款宋L EV全面升级加量不加价,仅18.98万元起

8月30日&#xff0c;2024成都车展正式开幕&#xff0c;备受期待的比亚迪王朝网B级先锋猎装SUV——2025款宋L EV正式上市&#xff0c;搭载“天神之眼”高阶智能驾驶辅助系统DiPilot 100&#xff0c;e平台3.0、CTB、云辇-C三大明星技术&#xff0c;并新增外观内饰配色。凭借智驾、…

【2024】Datawhale X 李宏毅苹果书 AI夏令营 Task2

本文是关于李宏毅苹果书”线性模型“学习内容的记录。 线性模型 线性模型&#xff08;linear model&#xff09;&#xff1a;将输入的特征 x x x&#xff08;或 x \bold{x} x&#xff09;乘上权重 ω \omega ω&#xff08;或 ω \bold{\omega} ω&#xff09;&#xff0c;再…

Python简易IDE工作界面制作

、 休闲一下&#xff0c;学习编程还是要学习一些界面编程&#xff0c;能够根据需要制作图形操作界面&#xff0c;这样我们开发的程序才能方便操作和使用&#xff0c;同时获得更友好的人机交互体验。下面是一个用PyQt5制作的简易界面&#xff0c;供大学参考。如下图所示&a…

罪人的终幕(原题)

题目背景 而我承诺你&#xff0c;一切都将在一场盛大的&#xff0c;如同戏剧般的审判中结束…… 小小地旋转&#xff0c;轻轻地跳跃&#xff0c;然后便是「罪人」的谢幕。 题目描述 定义函数 &#x1d44e;(&#x1d465;)a(x) 表示自然数 &#x1d465;x 的不同的质因子的和。…

数据增强在Sentence Transformers中的作用:提高句子评分任务的性能

Sentence Transformers 是一个强大的 Python 库&#xff0c;它基于 Transformer 模型架构&#xff0c;如 BERT、RoBERTa 和 XLM-RoBERTa 等&#xff0c;用于学习和操作句子级别的向量表示。这个库特别适合于处理自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;能够为…

实用好软-----电脑端 开源的视频无损剪切与合并工具

这个是一个开源项目LosslessCut 无损剪切就是基于关键帧的剪切&#xff0c;不需要重编码&#xff0c;因此速度非常快&#xff0c; 缺点就是切割时间无法达到非常精确&#xff0c;可能前后会有几秒的差距&#xff0c; 要做到精确的剪切&#xff0c;只能重编码。 LosslessCut在切…

学习之SQL语句之DQL(数据库查询语言)

DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据库中表的记录 查询关键字:SELECT 数据准备&#xff1a; CREATE TABLE emp ( id INT COMMENT “编号”, workno VARCHAR ( 10 ) COMMENT “工号”, NAME VARCHAR ( 10 ) COMME…

windows配置hadoop环境

目录 一、windows配置hadoop环境1、下载文件2、解压3、移动winutils.exe4、移动hadoop.dll5、配置代码内容 一、windows配置hadoop环境 1、下载文件 首先下载所需要的文件内容 共有三个文件&#xff0c;可以通过 这个链接 获得 2、解压 使用解压工具将 hadoop-3.0.0.tar.gz…

堆的时间复杂度分析

一&#xff0c;建堆的时间复杂度分析 堆是一颗完全二叉树&#xff0c;满二叉树又是一颗特殊的完全二叉树。 对于满二叉树来说&#xff0c;第一层的节点个数为2^0,第二层的节点个数为2^1,......所以可以得到第h层的节点个数为2^(h-1)。总结点个数N2^02^1...2^(h-1)2^h-1。那么就…

桌面日历工具

Desktop Calendar 官网 设置安装目录&#xff0c;防止默认装到C盘修改为自己想要安装的位置调整位置和大小

ip地址变化是什么意思?手机地址ip一直变化怎么办

IP地址作为互联网设备的唯一标识&#xff0c;‌其稳定性对于网络连接至关重要。‌然而&#xff0c;‌手机IP地址频繁变动可能带来一系列问题。‌本文将深入探讨IP地址变化的含义、‌IP地址频繁变动的原因&#xff0c;‌以及提供手机地址IP一直变化的有效应对策略。‌ 一、IP地址…

申请商标及版权时千万要注意字体!

近日有个渠道合作的朋友申请版权&#xff0c;就是几行文字&#xff0c;普推知产老杨一看这个字体有点特别&#xff0c;不是免费字体&#xff0c;一问也不是他们美工自己设计&#xff0c;是在网上找的字体&#xff0c;一检索果然是商业字体&#xff0c;赶紧建议换字体。 以前经常…

list类底层逻辑实现

list的底层逻辑是一个双向带头链表。那么list的底层其实就跟我们之前实现的带头双向链表相同&#xff0c;都是开辟一个一个单独的节点&#xff0c;最后再通过指针将各个单独的节点链接起来即可。 我们来类比之前编写的双向带头链表实现具体的内容。 创建一个list类的主体 就像我…

一个浏览器插件如何月入12万美元:深入了解 GoFullPage

一个浏览器插件如何月入12万美元&#xff1a;深入了解 GoFullPage 前言 GoFullPage 这个插件的诞生&#xff0c;源于其创作者 Peter Coles 的一个简单想法&#xff1a;解决一个他在日常开发工作中遇到的痛点。早在 2012 年&#xff0c;Coles 发现许多现有的网页截图工具无法完…

Qt 多个按钮,响应同一个点击事件

最近的一个需求&#xff0c;需要多个按钮响应同一个点击事件&#xff0c;并且要求能区分是哪个按钮点击的&#xff0c;看效果&#xff1a; 直接上代码&#xff1a; QList<QPushButton*> buttons findChildren<QPushButton*>();for (QPushButton* button : buttons…

Centos Stream9系统安装及网络配置详解

1.镜像下载 如未拥有系统镜像文件的伙伴可通过前往下面的连接进行下载&#xff0c;下载完成后需将其刻录至U盘中。 PS&#xff1a;该U盘应为空盘&#xff0c;刻录文件会导该盘格式化&#xff0c;下载文件选择dvd1.iso完整包&#xff0c;适用于本地安装。 下载地址&#xff1…

波导阵列天线单元学习笔记7 一种用直接金属激光烧结考虑的轻质量,宽带,双圆极化波导腔体阵列

摘要&#xff1a; 提出了一种工作在Ku频段的轻质量&#xff0c;宽带&#xff0c;双圆极化波导腔体阵列。为了获得双正交的线极化&#xff0c;基本的辐射单元是由两个波导馈电的方形腔体。通过恰当地对馈网进行调谐&#xff0c;可以获得对于两个正交极化的等辐同相辐射电场&…

学习之MySQL约束

概述 1、概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据 2、目的&#xff1a;保证数据库中数据的正确性&#xff0c;有效性和完整性 3、分类&#xff1a; 注意&#xff1a;约束是作用域表中字段上的&#xff0c;可以创建表/修改表的时候…

jenkins安装k8s插件发布服务

1、安装k8s插件 登录 Jenkins&#xff0c;系统管理→ 插件管理 → 搜索 kubernetes&#xff0c;选择第二个 Kubernetes&#xff0c;点击 安装&#xff0c;安装完成后重启 Jenkins 。 2、对接k8s集群、申请k8s凭据 因为 Jenkins 服务器在 kubernetes 集群之外&#xff0c;所以…