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);

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++进阶--C++11(2)

C11第一篇 C11是C编程语言的一个版本&#xff0c;于2011年发布。C11引入了许多新特性&#xff0c;为C语言提供了更强大和更现代化的编程能力。 可变参数模板 在C11中&#xff0c;可变参数模板可以定义接受任意数量和类型参数的函数模板或类模板。它可以表示0到任意个数&…

关于swagger配置

swagger有多种样式&#xff0c;有些比较难用&#xff0c;如下界面比较友好 1.推荐对应的jar包如下 <!--swagger相关--> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0<…

MYSQL 锁机制 与 MVCC多版本并发

MYSQL锁机制与优化以及MVCC底层原理 锁分类 乐观锁&#xff0c;悲观锁 从性能上分为乐观锁&#xff08;版本对比,版本一致就更新&#xff0c;不一致就不更新或CAS机制&#xff09;和悲观锁&#xff08;锁住资源等待&#xff09;&#xff0c;乐观锁适合读比较多的场景&#x…

Go 程序的启动流程【1/2】

Go 程序的启动流程 本文将以一个简单的 HelloWorld 程序为例&#xff0c;探究 Go 程序的启动流程 package mainfunc main() {_ "Hello World" }入口 我们先通过 go build . 将代码编译成可执行文件&#xff0c;众所周知&#xff0c;我们在一个 shell 中执行可执行…

jenkins+docker实现可持续自动化部署springboot项目

目录 一、前言 二、微服务带来的挑战 2.1 微服务有哪些问题 2.2 微服务给运维带来的挑战 三、可持续集成与交付概述 3.1 可持续集成与交付概念 3.1.1 持续集成 3.1.2 持续交付 3.1.3 可持续集成与交付核心理念 3.2 可持续集成优点 3.3 微服务为什么需要可持续集成 四…

echart 仪表盘实现指针的渐变色及添加图片

需求&#xff1a; 在仪表盘中设置指针为渐变色&#xff0c;并在仪表盘中间添加图片。 实现重点&#xff1a; 1、仪表盘指针渐变色的实现 渐变色通过设置pointer的itemStyle属性内的color实现&#xff0c;重点是echart版本&#xff0c;这个原本使用4.8.0的版本不起作用&#xff…

【Linux】环境基础开发工具使用——gcc/g++使用

Linux编译器-gcc/g使用 1. 背景知识 1. 预处理&#xff08;进行宏替换 ) 2. 编译&#xff08;生成汇编 ) 3. 汇编&#xff08;生成机器可识别代码&#xff09; 4. 连接&#xff08;生成可执行文件或库文件 ) 2. gcc如何完成 格式 gcc [ 选项 ] 要编译的文件 [ 选…

【Java+Springboot】----- 通过Idea快速创建SpringBoot项目操作方法

一、第一步&#xff1a; 点击选择【File】->【New】-> 【Project】 最后弹出[new Project]界面。 二、第二步&#xff1a; 1. 选择【Spring Initializr】 2. 然后选择【Project SDK】的版本 3. 然后 Choose Initializr Service URL 选择默认&#xff08;Default&#x…

降低笔记本电脑噪音的七种方法,看下有没有适合你的

序言 无论是玩游戏、浏览网络还是做严肃的工作,差不多都有这么一台笔记本电脑,它有足够的处理能力来处理几乎任何事情。不幸的是,它可能会变得非常大声,但有办法来遏制这种噪音。 清洁通风口和风扇,并使用硬表面 如果你的笔记本电脑现在比过去运行同样的软件时声音更大…

基于Springboot+Vue实现前后端分离社团管理系统

一、&#x1f680;选题背景介绍 &#x1f4da;推荐理由&#xff1a; 21世纪时信息化的时代&#xff0c;几乎任何一个行业都离不开计算机&#xff0c;将计算机运用于社团管理也是十分常见的。过去使用手工的管理方式对大学生社团进行管理&#xff0c;造成了管理繁琐、难以维护等…

迷茫下是自我提升

长夜漫漫&#xff0c;无心睡眠。心中所想&#xff0c;心中所感&#xff0c;忧愁当前&#xff0c;就执笔而下&#xff0c;写下这篇文章。 回忆过往 回想当初为啥学前端&#xff0c;走前端这条路&#xff0c;学校要求嘛&#xff0c;兴趣爱好嘛&#xff0c;还是为了钱。 时间带着…

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

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