- jdk-logging、log4j、logback日志介绍及原理
- commons-logging与jdk-logging、log4j1、log4j2、logback的集成原理
- slf4j与jdk-logging、log4j1、log4j2、logback的集成原理
- slf4j、jcl、jul、log4j1、log4j2、logback大总结
#2 slf4j
先从一个简单的使用案例来说明
##2.1 简单的使用案例
private static Logger logger=LoggerFactory.getLogger(Log4jSlf4JTest.class);
publicstaticvoidmain(String[] args){
if(logger.isDebugEnabled()){
logger.debug("slf4j-log4j debug message");
}
if(logger.isInfoEnabled()){
logger.debug("slf4j-log4j info message");
}
if(logger.isTraceEnabled()){
logger.debug("slf4j-log4j trace message");
}
}
上述Logger接口、LoggerFactory类都是slf4j自己定义的。
##2.2 使用原理
LoggerFactory.getLogger(Log4jSlf4JTest.class)的源码如下:
publicstatic Logger getLogger(String name){
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
上述获取Log的过程大致分成2个阶段
- 获取ILoggerFactory的过程 (从字面上理解就是生产Logger的工厂)
- 根据ILoggerFactory获取Logger的过程
下面来详细说明:
-
1 获取ILoggerFactory的过程
又可以分成3个过程:
-
1.1 从类路径中寻找org/slf4j/impl/StaticLoggerBinder.class类
ClassLoader.getSystemResources("org/slf4j/impl/StaticLoggerBinder.class")
如果找到多个,则输出 Class path contains multiple SLF4J bindings,表示有多个日志实现与slf4j进行了绑定
下面看下当出现多个StaticLoggerBinder的时候的输出日志(简化了一些内容):
SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [slf4j-jdk14-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
-
1.2 "随机选取"一个StaticLoggerBinder.class来创建一个单例
StaticLoggerBinder.getSingleton()
这里的"随机选取"可以见官方文档说明:
>SLF4J API is designed to bind with one and only one underlying logging framework at a time. If more than one binding is present on the class path, SLF4J will emit a warning, listing the location of those bindings
>The warning emitted by SLF4J is just that, a warning. Even when multiple bindings are present,SLF4J will pick one logging framework/implementation and bind with it. The way SLF4J picks a binding is determined by the JVM and for all practical purposes should be considered random
-
1.3 根据上述创建的StaticLoggerBinder单例,返回一个ILoggerFactory实例
StaticLoggerBinder.getSingleton().getLoggerFactory()
所以slf4j与其他实际的日志框架的集成jar包中,都会含有这样的一个org/slf4j/impl/StaticLoggerBinder.class类文件,并且提供一个ILoggerFactory的实现
-
-
2 根据ILoggerFactory获取Logger的过程
这就要看具体的ILoggerFactory类型了,下面的集成来详细说明
#3 slf4j与jdk-logging集成
##3.1 需要的jar包
- slf4j-api
- slf4j-jdk14
对应的maven依赖为:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.12</version>
</dependency>
##3.2 使用案例
private static final Logger logger=LoggerFactory.getLogger(JulSlf4jTest.class);
publicstaticvoidmain(String[] args){
if(logger.isDebugEnabled()){
logger.debug("jul debug message");
}
if(logger.isInfoEnabled()){
logger.info("jul info message");
}
if(logger.isWarnEnabled()){
logger.warn("jul warn message");
}
}
上述的Logger、LoggerFactory都是slf4j自己的API中的内容,没有jdk自带的logging的踪影,然后打出来的日志却是通过jdk自带的logging来输出的,如下:
四月 28, 2015 7:33:20 下午 com.demo.log4j.JulSlf4jTest main
信息: jul info message
四月 28, 2015 7:33:20 下午 com.demo.log4j.JulSlf4jTest main
警告: jul warn message
##3.3 使用案例原理分析
先看下slf4j-jdk14 jar包中的内容:
从中可以看到:
- 的确是有org/slf4j/impl/StaticLoggerBinder.class类
- 该StaticLoggerBinder返回的ILoggerFactory类型将会是JDK14LoggerFactory
- JDK14LoggerAdapter就是实现了slf4j定义的Logger接口
下面梳理下整个流程:
-
1 获取ILoggerFactory的过程
由于类路径下有org/slf4j/impl/StaticLoggerBinder.class,所以会选择slf4j-jdk14中的StaticLoggerBinder来创建单例对象并返回ILoggerFactory,来看下StaticLoggerBinder中的ILoggerFactory是什么类型:
privateStaticLoggerBinder(){ loggerFactory = new org.slf4j.impl.JDK14LoggerFactory(); }
所以返回了JDK14LoggerFactory的实例
-
2 根据ILoggerFactory获取Logger的过程
来看下JDK14LoggerFactory是如何返回一个slf4j定义的Logger接口的实例的,源码如下:
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(name); Logger newInstance = new JDK14LoggerAdapter(julLogger);
可以看到,就是使用jdk自带的logging的原生方式来先创建一个jdk自己的java.util.logging.Logger实例,参见jdk-logging的原生写法
然后利用JDK14LoggerAdapter将上述的java.util.logging.Logger包装成slf4j定义的Logger实例
所以我们使用slf4j来进行编程,最终会委托给jdk自带的java.util.logging.Logger去执行。
#4 slf4j与log4j1集成
##4.1 需要的jar包
- slf4j-api
- slf4j-log4j12
- log4j
maven依赖分别为:
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- slf4j-log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
##4.2 使用案例
-
第一步:编写log4j.properties配置文件,放到类路径下
log4j.rootLogger = debug, console log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n
配置文件的详细内容不是本博客关注的重点,不再说明,自行搜索
-
第二步:代码中如下使用
private static Logger logger=LoggerFactory.getLogger(Log4jSlf4JTest.class); publicstaticvoidmain(String[] args){ if(logger.isDebugEnabled()){ logger.debug("slf4j-log4j debug message"); } if(logger.isInfoEnabled()){ logger.info("slf4j-log4j info message"); } if(logger.isTraceEnabled()){ logger.trace("slf4j-log4j trace message"); } }
-
补充说明:
-
1 配置文件同样可以随意放置,如log4j1原生方式加载配置文件的方式log4j1原生开发
-
2 注意两者方式的不同:
slf4j: Logger logger=LoggerFactory.getLogger(Log4jSlf4JTest.class); log4j: Logger logger=Logger.getLogger(Log4jTest.class);
slf4j的Logger是slf4j定义的接口,而log4j的Logger是类。LoggerFactory是slf4j自己的类
-
##4.3 使用案例原理分析
先来看下slf4j-log4j12包中的内容:
- 的确是有org/slf4j/impl/StaticLoggerBinder.class类
- 该StaticLoggerBinder返回的ILoggerFactory类型将会是Log4jLoggerFactory
- Log4jLoggerAdapter就是实现了slf4j定义的Logger接口
来看下具体过程:
-
1 获取对应的ILoggerFactory
从上面的slf4j的原理中我们知道:ILoggerFactory是由StaticLoggerBinder来创建出来的,所以可以简单分成2个过程:
-
1.1 第一个过程:slf4j寻找绑定类StaticLoggerBinder
使用ClassLoader来加载 "org/slf4j/impl/StaticLoggerBinder.class"这样的类的url,然后就找到了slf4j-log4j12包中的StaticLoggerBinder
-
1.2 第二个过程:创建出StaticLoggerBinder实例,并创建出ILoggerFactory
源码如下:
StaticLoggerBinder.getSingleton().getLoggerFactory()
以slf4j-log4j12中的StaticLoggerBinder为例,创建出的ILoggerFactory为Log4jLoggerFactory
-
-
2 根据ILoggerFactory获取Logger的过程
来看下Log4jLoggerFactory是如何返回一个slf4j定义的Logger接口的实例的,源码如下:
org.apache.log4j.Logger log4jLogger; if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) log4jLogger = LogManager.getRootLogger(); else log4jLogger = LogManager.getLogger(name); Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
-
2.1 我们可以看到是通过log4j1的原生方式,即使用log4j1的LogManager来获取,引发log4j1的加载配置文件,然后初始化,最后返回一个org.apache.log4j.Logger log4jLogger,参见log4j1原生的写法
-
2.2 将上述的org.apache.log4j.Logger log4jLogger封装成Log4jLoggerAdapter,而Log4jLoggerAdapter是实现了slf4j的接口,所以我们使用的slf4j的Logger接口实例(这里即Log4jLoggerAdapter)都会委托给内部的org.apache.log4j.Logger实例
-
#5 slf4j与log4j2集成
##5.1 需要的jar包
- slf4j-api
- log4j-api
- log4j-core
- log4j-slf4j-impl (用于log4j2与slf4j集成)
对应的maven依赖分别是:
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.2</version>
</dependency>
<!-- log4j-slf4j-impl -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.2</version>
</dependency>
##5.2 使用案例
-
第一步:编写log4j2的配置文件log4j2.xml,简单如下:、
<?xml version="1.0" encoding="UTF-8"?><Configurationstatus="WARN"><Appenders><Consolename="Console"target="SYSTEM_OUT"><PatternLayoutpattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders><Loggers><Rootlevel="debug"><AppenderRefref="Console"/></Root></Loggers></Configuration>
-
第二步:使用方式
private static Logger logger=LoggerFactory.getLogger(Log4j2Slf4jTest.class); publicstaticvoidmain(String[] args){ if(logger.isTraceEnabled()){ logger.trace("slf4j-log4j2 trace message"); } if(logger.isDebugEnabled()){ logger.debug("slf4j-log4j2 debug message"); } if(logger.isInfoEnabled()){ logger.info("slf4j-log4j2 info message"); } }
##5.3 使用案例原理分析
先来看下log4j-slf4j-impl包中的内容:
- 的确是有org/slf4j/impl/StaticLoggerBinder.class类
- 该StaticLoggerBinder返回的ILoggerFactory类型将会是Log4jLoggerFactory(这里的Log4jLoggerFactory与上述log4j1集成时的Log4jLoggerFactory是不一样的)
- Log4jLogger就是实现了slf4j定义的Logger接口
来看下具体过程:
-
1 获取对应的ILoggerFactory
-
1.1 第一个过程:slf4j寻找绑定类StaticLoggerBinder
使用ClassLoader来加载 "org/slf4j/impl/StaticLoggerBinder.class"这样的类的url,然后就找到了log4j-slf4j-impl包中的StaticLoggerBinder
-
1.2 第二个过程:创建出StaticLoggerBinder实例,并创建出ILoggerFactory
log4j-slf4j-impl包中的StaticLoggerBinder返回的ILoggerFactory是Log4jLoggerFactory
-
-
2 根据ILoggerFactory获取Logger的过程
来看下Log4jLoggerFactory是如何返回一个slf4j定义的Logger接口的实例的,源码如下:
@Override protected Logger newLogger(final String name, final LoggerContext context){ final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name; return new Log4jLogger(context.getLogger(key), name); } @Override protected LoggerContext getContext(){ final Class<?> anchor = ReflectionUtil.getCallerClass(FQCN, PACKAGE); return anchor == null ? LogManager.getContext() : getContext(ReflectionUtil.getCallerClass(anchor)); }
-
2.1 我们可以看到是通过log4j2的原生方式,即使用log4j2的LoggerContext来获取,返回一个org.apache.logging.log4j.core.Logger即log4j2定义的Logger接口实例,参见log4j2原生的写法
-
2.2 将上述的org.apache.logging.log4j.core.Logger封装成Log4jLogger,而Log4jLogger是实现了slf4j的Logger接口的,所以我们使用的slf4j的Logger接口实例(这里即Log4jLogger)都会委托给内部的log4j2定义的Logger实例。
上述获取LoggerContext的过程也是log4j2的原生方式:
LogManager.getContext()
该操作会去加载log4j2的配置文件,引发log4j2的初始化
-
#6 slf4j与logback集成
##6.1 需要的jar包
- slf4j-api
- logback-core
- logback-classic(已含有对slf4j的集成包)
对应的maven依赖为:
<!-- slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
##6.2 使用案例
-
第一步:编写logback的配置文件logback.xml,简单如下:
<?xml version="1.0" encoding="UTF-8"?><configuration><appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><rootlevel="DEBUG"><appender-refref="STDOUT" /></root></configuration>
-
第二步:使用方式
private static final Logger logger=LoggerFactory.getLogger(LogbackTest.class); publicstaticvoidmain(String[] args){ if(logger.isDebugEnabled()){ logger.debug("slf4j-logback debug message"); } if(logger.isInfoEnabled()){ logger.info("slf4j-logback info message"); } if(logger.isTraceEnabled()){ logger.trace("slf4j-logback trace message"); } }
##6.3 使用案例原理分析
先来看下logback-classic包中与slf4j集成的内容:
-
的确是有org/slf4j/impl/StaticLoggerBinder.class类
-
该StaticLoggerBinder返回的ILoggerFactory类型将会是LoggerContext(logback的对象)
-
logback自己定义的ch.qos.logback.classic.Logger类就是实现了slf4j定义的Logger接口
-
1 获取对应的ILoggerFactory
-
1.1 第一个过程:slf4j寻找绑定类StaticLoggerBinder
使用ClassLoader来加载 "org/slf4j/impl/StaticLoggerBinder.class"这样的类的url,然后就找到了logback-classic包中的StaticLoggerBinder
-
1.2 第二个过程:创建出StaticLoggerBinder实例,并创建出ILoggerFactory
logback-classic包中的StaticLoggerBinder返回的ILoggerFactory是LoggerContext(logback的对象)
创建出单例后,同时会引发logback的初始化,这时候logback就要去寻找一系列的配置文件,尝试加载并解析。
-
-
2 根据ILoggerFactory获取Logger的过程
来看下LoggerContext(logback的对象)是如何返回一个slf4j定义的Logger接口的实例的:
该LoggerContext(logback的对象)返回的ch.qos.logback.classic.Logger(logback的原生Logger对象)就是slf4j的Logger实现类。
相关推荐
NULL 博文链接:https://tristan-s.iteye.com/blog/1966020
4. SLF4J与其他日志框架的关系: - **适配器**:SLF4J提供了适配器模块,如`slf4j-log4j12`,用于将SLF4J接口绑定到Log4j实现。 - **桥接器**:对于已使用特定日志系统的代码,SLF4J还提供了桥接器,如`jul-to-slf...
视频详细讲解,需要的小伙伴自行网盘下载,链接见附件,... logback-access使用章节七:Log4j21. 快速入门2. 配置文件3. 异步日志4. 性能介绍章节八:SpringBoot使用日志1. springBoot日志设计2. springBoot日志使用
- 如果需要与现有使用Log4j的项目集成,则可能需要考虑Log4j2。 #### 3. 如何选择合适的日志框架 - **评估项目需求**: - 考虑项目的规模、日志需求的复杂度以及团队的技术背景。 - 新项目建议采用SLF4J + ...
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
《基于YOLOv8的智慧社区独居老人生命体征监测系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计
Android Studio Meerkat 2024.3.1 Patch 1(android-studio-2024.3.1.14-mac.dmg)适用于macOS Intel系统,文件使用360压缩软件分割成两个压缩包,必须一起下载使用: part1: https://download.csdn.net/download/weixin_43800734/90557060 part2: https://download.csdn.net/download/weixin_43800734/90557056
侧轴承杯加工工艺编制及夹具设计.zip
NASA数据集锂电池容量特征提取(Matlab完整源码和数据) 作者介绍:机器学习之心,博客专家认证,机器学习领域创作者,2023博客之星TOP50,主做机器学习和深度学习时序、回归、分类、聚类和降维等程序设计和案例分析,文章底部有博主联系方式。从事Matlab、Python算法仿真工作8年,更多仿真源码、数据集定制私信。
板料折弯机液压系统设计.zip
C6150车床的设计.zip
机器学习之KNN实现手写数字
python爬虫;智能切换策略,反爬检测机制
mpls-vpn-optionA-all
56tgyhujikolp[
GB 6442-86企业职工伤亡事故调查分析规则.pdf
汽车液压式主动悬架系统的设计().zip
2000-2024年各省专利侵权案件结案数数据 1、时间:2000-2024年 2、来源:国家知识产权J 3、指标:专利侵权案件结案数 4、范围:31省 5、用途:可用于衡量知识产权保护水平
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
内容概要:本文档详细复现了金融数学课程作业,涵盖欧式看涨期权定价和投资组合优化两大部分。对于欧式看涨期权定价,分别采用Black-Scholes模型和蒙特卡洛方法进行了计算,并对彩虹期权进行了基于最大值的看涨期权定价。投资组合优化部分则探讨了最小方差组合、给定收益的最小方差组合、最大效用组合以及给定风险的最大收益组合四种情形,还对比了拉格朗日乘数法和二次规划求解器两种方法。文中不仅提供了详细的MATLAB代码,还有详尽的中文解释,确保每一步骤清晰明了。 适合人群:金融工程专业学生、量化分析师、金融数学爱好者。 使用场景及目标:①帮助学生理解和掌握金融衍生品定价的基本原理和方法;②为从事量化分析的专业人士提供实用工具和技术支持;③作为教学材料辅助高校教师讲授相关内容。 其他说明:文档还包括了完整的论文结构建议,从封面页到结论,再到附录,涵盖了所有必要元素,确保提交的作业符合学术规范。此外,还特别强调了数据预处理步骤,确保代码可以顺利运行。