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

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

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.kler.cn/news/284609.html

相关文章:

  • 软件测试面试八股文
  • LeetCode面试题Day18|LC61 旋转链表
  • 【web开发】Spring Boot 快速搭建Web项目(二)
  • Getting RateLimitError while implementing openai GPT with Python
  • openshift node NotReady kubelet http: TLS handshake error
  • SAP 有趣的‘bug‘ 选择屏幕输入框没了
  • 应用案例|亚克力板CNC加工自动化上下料
  • (四)进入MySQL 【事务】
  • 私有ip(介绍,地址范围),私网和公网的关系(访问外部网站的过程,NAT技术)
  • 三种评估金融风险的方法的具体Python实现:Stress Testing、Scenario Analysis和Sensitivity Analysis
  • 乐凡三防:工业界的硬核产品——重新定义三防平板的极限
  • Scrcpy手机投屏投屏到电脑上(windows/mac)
  • Python实现t-分布随机邻域嵌入(t-SNE)降维算法
  • 手机FM LNA方案设计
  • 【IEEE独立出版 | 往届快至会后2个月检索】2024年第四届电子信息工程与计算机科学国际会议(EIECS 2024,9月27-29)
  • vue-echarts :知识图谱可视化,动态更新 动态赋值series,更新options
  • GESP C++ 四级 编程题 洛谷习题集
  • 【JavaScript】JavaScript模块化开发:ES6模块与CommonJs的对比与应用
  • macos 10.15 Catalina 可用docker最新版本 Docker Desktop 4.15.0 (93002) 下载地址与安装方法
  • 5W爆了,建议紧盯这个方向!!
  • OWOD环境配置和训练细节
  • 「OC」初识MVC —— 简单学习UITableView的解耦
  • opencv之阈值处理
  • 网优学习干货:2.6G仿真操作(2)
  • 信息安全--(四)网络安全体系与安全模型(二)
  • Linux系统安装nginx
  • 如何申请 Midjourney API ,看这篇文章就够了
  • Web自动化测试实战--博客系统
  • css中 display block属性的用法
  • docker里装mysql