java日志框架简介

文章目录

    • 概要
    • 常用日志框架
        • 常见框架有以下:
        • slf4j StaticLoggerBinder绑定过程(slf4j-api-1.7.32 )
        • JCL 运行时动态查找过程:(commons-logging-1.2)
        • 使用桥接修改具体日志实现
    • 一行日志的打印过程
    • 开源框架日志模块
        • Spring && Springboot
        • Mybatis

概要

文章简要梳理java常见日志框架,学习其背景和实现,通过阅读文章可以掌握如下知识点:
1、学习目前常用日志接口和实现框架,了解其功能作用实现原理。
2、掌握slf4j和logback的日志组合框架,debug跟踪一行日志的打印流程。
3、学习日常开发框架如Spring, Mybatis,了解大佬是如何实现日志模块。

常用日志框架

一、日志框架主要分为两类,日志门面接口和日志具体实现。

  1. 日志门面接口,如JCL 和 slf4j
    1)应用面向接口编程,接口不易变动。
    2)面向接口,可以通过绑定或桥接切换不同日志系统实现。
  2. 日志具体实现,如log4j JUL logback log4j2等。
    1)专注于实现日志打印功能实现。
    2)提供各种日志配置和功能特性。
常见框架有以下:
框架功能描述
log4j实现Apache 早期开源日志框架
JUL
java.util.logging
实现Sun官方自带日志框架,JDK1.4引入
JCL
Apache Commons Logging
接口Apache 的日志门面,可以切换log4j或JUL具体日志实现
slf4j-api接口简单java日志接口,日志门面,简单易用
logback实现高性能日志实现框架,包含一下模块:
logback-core:基础模块
logback-classic:日志实现模块
log4j2实现Apache 的开源日志框架,性能优化版本
slf4j-jcl
slf4j-jdk14
slf4j-log412
绑定slf4j-api具体绑定实现
jcl-over-slf4j
jul-to-slf4j
log4j-over-slf4j
桥接其他日志框架slf4j-api具体绑定实现

日志分层可参考如下图:
日志分层
绑定查找具体实现过程:

slf4j StaticLoggerBinder绑定过程(slf4j-api-1.7.32 )
  1. 如果未初始化,执行初始化:LoggerFactory#performInitialization。
  2. 扫描类文件:org/slf4j/impl/StaticLoggerBinder.class,报告不存在类或存在多个类歧义。
  3. 由具体实现框架提logback-classic提供StaticLoggerBinder,触发其静态绑定。

TIP:sl4j-api 2.x版本使用SPI org.slf4j.spi.SLF4JServiceProvider,
logback提供service实现 ch.qos.logback.classic.spi.LogbackServiceProvider

JCL 运行时动态查找过程:(commons-logging-1.2)
  1. System.getProperty读org.apache.commons.logging.LogFactory
  2. 读META-INF/services/org.apache.commons.logging.LogFactory
  3. 读取类路径下commons-logging.properties,key=org.apache.commons.logging.LogFactory
  4. 使用默认实现org.apache.commons.logging.impl.LogFactoryImpl,按下面顺序获取Logger:
    Log4JLogger
    Jdk14Logger
    Jdk13LumberjackLogger
    SimpleLog
使用桥接修改具体日志实现

如果项目依赖第三包已经其他日志框架接口,那么这时候如何规范化统一日志实现,这时候可以使用桥接:
桥接

一行日志的打印过程

下面介绍一行日志的打印过程,以目前市面常见搭配组合slf4j-api-1.7.32 logback-classic-1.2.12为例,代码只展示部分关键源码:
1、LoggerFactory#getLogger(Class<?> clazz),
获取指定名称Logger。

public static Logger getLogger(String name) {
     ILoggerFactory iLoggerFactory = getILoggerFactory();
     return iLoggerFactory.getLogger(name);
}

2、LoggerFactory#getILoggerFactory,
获取日志工厂LoggerFactory,如果未初始化则执行performInitialization完成日志实现绑定。

public static ILoggerFactory getILoggerFactory() {
     if (INITIALIZATION_STATE == UNINITIALIZED) {
         synchronized (LoggerFactory.class) {
             if (INITIALIZATION_STATE == UNINITIALIZED) {
                 INITIALIZATION_STATE = ONGOING_INITIALIZATION;
                 performInitialization();
             }
         }
     }
     ……
 }

3、LoggerFactory#bind,
绑定到具体日志实现,扫描类路径资源文件org/slf4j/impl/StaticLoggerBinder.class,加载完成绑定。

private final static void bind() {
     staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
     reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
     ……
}

4、StaticLoggerBinder.getSingleton().getLoggerFactory(),
具体日志实现绑定初始化,如绑定到logback的StaticLoggerBinder,调用logback实现类StaticLoggerBinder#init->ContextInitializer#autoConfig,实现具体绑定类初始化。
logback ContextInitializer配置
1)ContextInitializer#configureByResource,按顺序检查如下配置文件logback-test.xml,logback.groovy,logback.xml,则存在使用配置文件。
2)SPI 加载是否指定Configurator配置实现,是则使用该配置实现。
3)如果上述都没有,则使用默认配置实现BasicConfigurator。

public ILoggerFactory getLoggerFactory() {
        public void autoConfig() throws JoranException {
        StatusListenerConfigHelper.installIfAsked(loggerContext);
        URL url = findURLOfDefaultConfigurationFile(true);
        if (url != null) {
            configureByResource(url);
        } else {
            Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);
            if (c != null) {
                try {
                    c.setContext(loggerContext);
                    c.configure(loggerContext);
                } catch (Exception e) {
                    throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass()
                                    .getCanonicalName() : "null"), e);
                }
            } else {
                BasicConfigurator basicConfigurator = new BasicConfigurator();
                basicConfigurator.setContext(loggerContext);
                basicConfigurator.configure(loggerContext);
            }
        }
    }
}

5、LoggerContext#getLogger,
获取指定名称logger。

public final Logger getLogger(final String name) {
	……
	synchronized (logger) {
        childLogger = logger.getChildByName(childName);
        if (childLogger == null) {
            childLogger = logger.createChildByName(childName);
            loggerCache.put(childName, childLogger);
            incSize();
        }
    }
	……
}

6、Logger#info,
具体一行日志打印,以Info级别日志打印为例:

  1. 全局过滤器 TurboFilter判断是否打印
    2)构建LoggingEvent,将日志事件投递给Appender#doAppend
    3)调用Appender配置过滤Filter判断是否打印
    4)交给具体Appender完成日志事件处理,实现有:
    控制台ConsoleAppender
    文件FileAppender
    归档文件RollingFileAppender
    异步AsyncAppender
    数据库DBAppender
    等等。
private void filterAndLog_0_Or3Plus(final String localFQCN, final Marker marker, final Level level, final String msg, final Object[] params,
                    final Throwable t) {

    final FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);

    if (decision == FilterReply.NEUTRAL) {
        if (effectiveLevelInt > level.levelInt) {
            return;
        }
    } else if (decision == FilterReply.DENY) {
        return;
    }

    buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
}

其他日志打印格式化相关:
Appender
Encoder
Layout

开源框架日志模块

Spring && Springboot

Spring使用JCL门面,如果不引入commons-logging或其他实现jar。按上面描述会使用JDK自带JUL作为日志实现。

Springboot提供logging的starter。
spring-boot-starter-logging, 默认使用logback实现,桥接了log4j和JUL到slf4j。

TIP: 如果项目有引入commons-logging, 还需要手动引入桥接 jcl-over-slf4j

<dependencies>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-to-slf4j</artifactId>
      <version>2.13.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jul-to-slf4j</artifactId>
      <version>1.7.30</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

Springboot框架日志初始化流程如下:
1、监听Spring容器生命周期
在这里插入图片描述
2)LoggingSystem#get,加载具体日志系统实现,默认按如下优先级:
在这里插入图片描述
3)日志系统切入Springboot应用生命周期
监听ApplicationStartingEvent,触发LoggingSystem#beforeInitialize
监听ApplicationEnvironmentPreparedEvent,触发LoggingSystem#initialize
监听onApplicationPreparedEvent,注册日志系统相关单例bean到Spring容器
监听ContextClosedEvent/onApplicationFailedEvent, 日志系统清理

Mybatis

Mybatis对常见日志框架包装一层,使用自定义日志接口,通过配置或默认规则设置具体日志实现框架:
mybatis日志模块
1)尝试加载实现,按如下顺序优先级加载。
在这里插入图片描述

2)如果通过配置指定具体实现,则使用具体实现。

Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【图论】【分类讨论】LeetCode3017按距离统计房屋对数目

本文涉及的知识点 图论 分类讨论 本题同解 【差分数组】【图论】【分类讨论】【整除以2】3017按距离统计房屋对数目 LeetCode3017按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 …

服务效率飙升!2024最新Zoho Desk功能解析

2024年&#xff0c;立足于服务经济浪潮&#xff0c;如何为您的客户提供优质服务&#xff0c;高效解决客户工单&#xff0c;赢得客户美誉度&#xff0c;是当下各行企业的着力点。 在企业中&#xff0c;与客户发生最直接接触的就是客户服务部门。规范化客服部门业务流程&#xf…

【JavaWeb】Day36.MySQL概述——数据库设计-DDL(三)

查询 关于表结构的查询操作&#xff0c;工作中一般都是直接基于图形化界面操作。 1.查询当前数据库所有表 2.查看指定表结构 3.查询指定表的建表语句 注意&#xff1a;23版的点击导航中的转到DDL 修改 关于表结构的修改操作&#xff0c;一般也是直接基于图形化界面操作。 添…

LeetCode---127双周赛

题目列表 3095. 或值至少 K 的最短子数组 I 3096. 得到更多分数的最少关卡数目 3097. 或值至少为 K 的最短子数组 II 3098. 求出所有子序列的能量和 一、或值至少k的最短子数组I&II 暴力的做法大家都会&#xff0c;这里就不说了&#xff0c;下面我们来看看如何进行优化…

彩虹易支付接口配置

支付通道配置 基本概念 彩虹易支付系统有强大的支付接口扩展能力&#xff0c;首先需要明白以下几个概念。 支付方式&#xff1a; 支付方式用于定义发起支付的调用值&#xff08;在前台开发文档里面显示&#xff09;与支付方式名称。目前系统自带6种支付方式&#xff0c;它们的…

腾讯云最新活动及优惠券领取指南

随着云计算技术的不断发展和普及&#xff0c;越来越多的企业和个人选择将业务迁移到云端。腾讯云作为国内领先的云计算服务提供商&#xff0c;经常推出各种优惠活动&#xff0c;以帮助用户降低成本、提高效率。本文将为大家详细介绍腾讯云的最新活动及优惠券领取指南&#xff0…

猫头虎分享已解决Bug || **Error (通用错误)** 全景剖析

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

数学杂谈之一:数学的形态

数学杂谈之一&#xff1a;数学的形态 数学的形态可以根据不同的角度和视角进行分类和描述。下面是从数学的发展和应用的不同角度进行的分类&#xff1a; 原始形态&#xff1a;原始形态是指数学的发展和应用起源的形态。它涉及到数学的理论构建、证明和发现过程&#xff0c;是数…

目标追踪StrongSORT——基于DeepSORT重大升级提高多目标跟踪的准确性和鲁棒性

1、概述 1.1 DeepSORT DeepSORT算法是在SORT基础上发展起来的一种多目标跟踪算法。SORT算法结合了目标检测器和跟踪器&#xff0c;其中跟踪器的核心是卡尔曼滤波和匈牙利算法。卡尔曼滤波用于预测目标在下一帧的位置和状态&#xff0c;而匈牙利算法则用于将预测状态与实际检测…

【Linux】Linux C 编程

在 Windows 下编程首先就是安装对应的 IDE &#xff0c;然后在 IDE 里面进行代码编写和编译&#xff0c;但是在 Linux 下&#xff0c;这两个部分是分开的&#xff0c;比如我们可以使用 vim 编辑器编写代码&#xff0c;然后用 gcc 编译器编译代码。Ubuntu 下有一些可以进行编程的…

Azkaban集群模式部署详细教程

序言 Azkaban是一个用于工作流程调度和任务调度的开源工具&#xff0c;它可以帮助用户轻松地管理和监控复杂的工作流程。Azkaban的架构设计旨在提供高度可扩展性和可靠性&#xff0c;同时保持易用性和灵活性。 Azkaban的架构可以分为三个主要组件:Executor、Web Server和db数据…

Python-VBA编程500例-033(入门级)

角色定位(Role Positioning)在编程中的实际应用场景主要体现在以下几个方面&#xff1a; 1、权限管理&#xff1a;在开发企业级应用或复杂的系统时&#xff0c;角色定位用于定义和管理用户的权限。例如&#xff0c;一个系统可能有管理员、普通用户、访客等不同角色&#xff0c…

Linux网络管理类命令

ping -c&#xff1a;指定次数 -i n&#xff1a;指定发送频率 n 秒 -t&#xff1a;指定 TTL 值 -s&#xff1a;指定发送包的大小 ifconfig iproute netstat -anltp ss ssh 主机名 SCP wget nmap -A: 全面扫描 -p &#xff1a;端口 80 22-80 80,25,443 -sP &#xf…

利用native的方式实现跨线程调用

简介 在OpenHarmony应用开发实践中&#xff0c;经常会遇到一些耗时的任务&#xff0c;如I/O操作、域名解析以及复杂计算等。这些任务如果直接在主线程中执行&#xff0c;将会严重阻塞主线程&#xff0c;影响后续任务的正常流程&#xff0c;进而导致用户界面响应延迟甚至卡顿。…

【学习笔记】Elsevier的Latex模板文件(附网址)

注&#xff1a;这是一篇没有技术含量的水文&#xff0c;主要是看有人下载下来&#xff0c;居然当成资源需要积分才能下载。我觉得不行&#xff0c;故提供原始下载地址供查阅使用。 链接: 上述图片所示网址&#xff1a;链接直达

Redis(性能管理、主从复制、哨兵模式)概述及部署

目录 一、性能管理 1、查看Redis内存使用 2、内存碎片率 3、跟踪内存碎片率 4、内存使用率 5、内回收key 二、Redis集群有三种模式 三、Redis主从复制 1、主从复制的概念 2、主从复制的作用 3、主从复制的流程 4、搭建Redis主从复制 1.环境准备 2.安装Redis&#…

在团队管理过程中,怎样能够让员工更容易接受和执行反馈呢?

让员工更容易接受和执行反馈&#xff0c;关键在于建立一种开放、积极且互相尊重的沟通氛围。 确保反馈的针对性和具体性是关键。 员工需要清楚了解他们的表现如何&#xff0c;以及他们需要改进的地方在哪里。因此&#xff0c;反馈内容应具体明确&#xff0c;避免模糊或笼统的表…

Python零基础到精通

Python入门指南 欢迎进入 Python 领域。作为程序员&#xff0c;我们总是在寻找能提高效率、编写优雅的代码的工具&#xff0c;而 Python 正是其中之一。你即将探索一种强大而灵活的编程语言&#xff0c;它被广泛应用于各种领域&#xff0c;从网站开发到数据科学&#xff0c;再到…

基础总结篇:Activity生命周期

private int param 1; //Activity创建时被调用 Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, “onCreate called.”); setContentView(R.layout.lifecycle); Button btn (Button) findViewById(R.id.…

【开源语音项目OpenVoice](一)——实操演示

目录 一、前菜 1、Python选择 2、pip源切换 3、ffmpeg配置问题 4、VSCode添加Jupyter扩展 二、配置虚拟环境 1、下载源码 方法一 直接下载源码压缩包 方法二 使用git 1&#xff09;git加入鼠标右键 2&#xff09;git clone源码 2、VSCode出场 1&#xff09;创建pyth…