暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

JAVA日志体系-SLF4J如何桥接日志实现

领创集团Advance Group 2022-03-24
996

导语:在我们的日常开发中问题的发现与追踪与日志的使用密不可分,但在不同企业的系统架构体系中依赖的日志架构有所不同,很多开源框架以及它们不同版本选择依赖的日志架构也有所不同。现有的主流日志实现有:log4j、log4j2、commons logging、logback等。slf4j是如何实现日志实现的依赖切换的,带着这些疑问我们一起了解一下目前常用的java日志体系。


日志框架的类别

  1. 门面型

面对市面多种框架的出现,也出现了如同JDBC是一种日志api标准,其作用是在不改动api的前提下切换日志的实现。主要有:

  • JCL(Commons Logging)
    Apache基金会推出的一套JAVA日志接口。
  • SLF4J(Simple Logging Facade for Java)
    ceki推出的一套日志门面接口,通过桥接方式对接各种日志实现,slf4j的简洁设计思想以及对各种日志框架的兼容使其成为主流门面日志框架,其本身只提供一个slf4j-api-vesion.jar包,提供业务使用的日志抽象接口。针对不同的日志实现框架封装了不同的桥接组件,通过引用这些桥接组件灵活的选择适合的日志记录框架。

  2.记录型 

真正的日志实现,我们通常会根据框架的性能、功能等方面选择其中一种。主要有:

  • Log4j:由ceki首创,后成为Apache基金会顶级项目的日志框架,后被log4j2替代。

  • Jul(Java Util Logging): JDK在1.4版本推出的日志记录工具。

  • Logback:由ceki推出一个“可靠、通用、快速而又灵活的Java日志框架”,其直接实现了slf4j接口。

  • log4j2:由apache基金参考logback并做一系列优化推出的日志实现框架,且与log4j不兼容。


桥接组件介绍


桥接过程源码分析

1. 核心类介绍

  • org.slf4j.Logger: 主要调用者入口,提供丰富的日志记录方法。

  • org.slf4j.ILoggerFactory: 提供获取Logger实例方法,具体工厂类实现由桥接组件实现。

  • org.slf4j.LoggerFactory:ILoggerFactory的包装类,在编译时与各种日志组件ILoggerFactory实现绑定。其默认绑定实现是NOPLoggerFactory。

  • org.slf4j.impl.StaticLoggerBinder:绑定ILoggerFactory实例与LoggerFactory;由各个桥接包实现并定义在org.slf4j.impl包下,注意在slf4j-api-version.jar中不存在该类。

  • org.slf4j.helpers.NOPLogger:Slf4j的默认日志实现,不输出任何日志

2. 源码分析 - 无日志实现依赖

  • gradle 依赖 - 仅依赖slf4jApi 

    dependencies {
    implementation 'org.slf4j:slf4j-api:1.7.33'
    }
    • 应用程序入口

    • 通过org.slf4j.LoggerFactory#getLogger静态方法获取Logger实例

    • 通过LoggerFactory#getILoggerFactory方法获取具体Logger工厂实现类

    • 首次调用,通过LoggerFactory#performInitialization方法初始化,并通过LoggerFactory#bind方法进行实现类绑定

    • 通过ClassLoader加载org/slf4j/impl/StaticLoggerBinder.class,因为没有依赖任何桥接包,因此加载不到任何StaticLoggerBinder。

    • 因为不存在StaticLoggerBinder类,抛出NoClassDefFoundError异常,并将state设置成4(使用默认的NOPLogger),同时可在console看到相应日志。

    • 根据status返回默认的NOPLoggerFactory

    • 最终应用入口使用的Logger是由NOPLoggerFactory#getLogger获取的NOPLogger,其内部所有日志输出方法均为空实现。

    源码分析 - 桥接LogBack

    • gradle依赖 - 添加logback桥接包的依赖

      dependencies {    
      implementation 'org.slf4j:slf4j-api:1.7.33'
      // 内部依赖logback-core
      implementation 'ch.qos.logback:logback-classic:1.2.10'
      }
      • 前面逻辑同上,我们直接看bind()方法中加载staticLoggerBinder的逻辑。可见staticLoggerBinder被ClassLoader加载到,同时state设置为3(成功)。

      • 使用单例的方式从StaticLoggerBinder具体实现类获取LoggerFactory

      • 最终应用入口使用的logger是ch.qos.logback.classic包的loggerContext(implements ILoggerFactory),使用默认格式输出如下:

      源码分析 - 桥接多种实现

      我们的系统可能存在多层依赖,而每种依赖中可能依赖了自己选择的日志实现,那么这种存在多种日志实现,slf4j会怎么处理呢?

      • gradle依赖 - 添加jul、log4j2、logback日志实现桥接包的依赖

        dependencies {
        implementation 'org.slf4j:slf4j-api:1.7.33'
        // 桥接logback
        implementation 'ch.qos.logback:logback-classic:1.2.10'
        implementation 'org.apache.logging.log4j:log4j-core:2.17.1'
        // 桥接log4j2
        implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.1'
        // 桥接jdk-log
        implementation 'org.slf4j:slf4j-jdk14:1.7.33'
        }

        • 我们依旧看bind()方法中加载staticLoggerBinder的逻辑。ClassLoader加载到3个staticLoggerBinder类(console会输出multiple bind警告),由StaticLoggerBinder.getSingleton()可见,程序具体使用哪个StaticLoggerBinder实现由JVM随机选择(我们尽量剔除没必要的依赖,以免出现魔幻问题)。

        • 最终应用入口使用的logger是ch.qos.logback.classic包的loggerContext,默认输出格式为如下:


        Springboot (2.3.x)默认日志实现

        从springboot-start-logging包可见其默认依赖的日志实现应该是logback。

        应用系统输出日志可见,其使用的也是logback日志实现。


        参考资料

        slf4j官网:https://www.slf4j.org/

        slf4j官方桥接介绍:https://www.slf4j.org/legacy.html

        logback官网:https://logback.qos.ch/

        JCL官网:https://commons.apache.org/proper/commons-logging/

        Log4j2官网:https://logging.apache.org/log4j/2.x/

        关于领创集团
        (Advance Intelligence Group)
        领创集团成立于 2016年,致力于通过科技创新的本地化应用,改造和重塑金融和零售行业,以多元化的业务布局打造一个服务于消费者、企业和商户的生态圈。集团旗下包含企业业务和消费者业务两大板块,企业业务包含 ADVANCE.AI 和 Ginee,分别为银行、金融、金融科技、零售和电商行业客户提供基于 AI 技术的数字身份验证、风险管理产品和全渠道电商服务解决方案;消费者业务 Atome Financial 包括亚洲领先的先享后付平台 Atome 和数字金融服务。2021年 9月,领创集团宣布完成超4亿美元 D 轮融资,融资完成后领创集团估值已超 20亿美元,成为新加坡最大的独立科技创业公司之一。
        往期回顾
        BREAK AWAY
        领创头条 | 初级工程师建议收藏|企业级APIs安全实践指南 

        技术创想 | shiro550和721反序列化简谈


        技术创想 | DeepRacer 自动驾驶赛车冠军队技术分享




        文章转载自领创集团Advance Group,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论