java中log使用小结
一、概述
本文乃博主呕心沥血之作,一文搞清楚java所有日志框架。阅读前请先收藏。
1.1. 核心日志框架
核心日志框架,就是实际干活的日志框架。总体而言,市面上的使用日志框架体系主要有
- jul(java.util.logging) jdk1.4加入,为了对抗log4j,效率灵活性较差使用较少
- log4j 最广泛应用的日志框架,成为事实上的标准
- logback 基于slf4j-api接口实现,性能高于log4j
- log4j2 重写了log4j,性能高于log4j,logback
1.2 门面日志框架
核心日志框架能单独使用,但多框架集成使用时使用会有冲突。所以出现了门面日志框架。
门面日志框架特征有:
- 提供统一日志使用接口,核心日志框架去实现门面日志框架的接口。
- 应用不使用具体的核心日志框架,只使用门面日志框架。不依赖核心日志框架,只依赖门面日志框架。
- 这样就算底层换核心框架依赖,不影响现有日志的使用。
目前主流的门面框架主要有JCL和SLF4J:
- JCL(commings-log) Apache提供的comming-log
- SLF4J(simple log facade for java) Log4j、Logback、Log4j2作者提供
二、最佳实践
2.1 核心日志框架API包
各核心日志框架单独使用的依赖,demo里的version不限制。
- log4j
<!-- log4j的API包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
- log4j2
<!-- log4j2的两个API包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.9.1</version> </dependency>
- logback
<!-- logback的两个API包--> <!-- logback无法单独使用,只能和slf4j集合使用--> <!-- logback-classic实现了slf4j向logback的转换--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
- jul
jdk自带API,无依赖包
2.2 门面日志框架依赖
- jcl
<!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency>
slf4j
<!-- slf4j的API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency>
2.3 集成使用
2.3.1 集成jcl
总结如下:
- JCL集成其他日志框架,只有log4j/jul没有中间包
- JCL同时集成其他核心日志框架,使用JCL打印日志优先级: log4j2>log4j>jul
- JCL同时和jul/log4j/log4j2集成,jcl没有全局整合能力各日志全部生效
- JCL同时和jul/log4j/log4j2集成,此时使用JCL打印日志生效的是log4j2
- slf4j转向JCL前提是没有slf4j的实现框架依赖,否则slf4j实现优先级更高
集成jul
默认jcl就是集成jul的
<!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency>
集成log4j
<!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <!-- log4j的API --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
集成log4j2
<!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!-- log4j2的两个API包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.9.1</version> </dependency> <!-- 适配包:jcl转向log4j2 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>2.9.1</version> </dependency>
集成slf4j
<!-- slf4j的API包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:slf4j转向jcl --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jcl</artifactId> <version>1.7.25</version> </dependency> <!-- JCL的实现包,可以为jul/log4j/logj42,这里省略。默认是jul -->
2.3.2 集成slf4j
2.3.2.1 slf4j集成单一框架
总结如下:
- SLF4J转向其他日志框架都需要对应适配包
- 其他日志框架经过JCL转向SLF4J时,一般可以省略JCL通过匹配包直接转向SLF4J不再展开
- SLF4J和具体日志框架的双向适配包不能同时存在(需排除冲突),否则会循环依赖栈溢出.包括:
- slf4j-jdk14和jul-to-slf4j(运行时直接栈溢出)
- slf4j-log4j12和log4j-over-slf4j(启动会检测报错)
- log4j-slf4j-impl和log4j-to-slf4j(运行时直接栈溢出)
- slf4j-jcl和jcl-over-slf4j(启动会检测报错)
集成jul
<!-- slf4j的API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:slf4j转向jul --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:jul转向slf4j --> <!-- 若和slf4j-jdk14包同时存在会造成jul和slf4j循环转化造成栈溢出,所以要排除 --> <!-- <dependency>--> <!-- <groupId>org.slf4j</groupId>--> <!-- <artifactId>jul-to-slf4j</artifactId>--> <!-- <version>1.7.25</version>--> <!-- </dependency>-->
集成log4j
<!-- log4j的API包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- slf4j的API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- log4j对slf4j的实现:log4j转slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:log4j转向slf4j --> <!-- log4j-over-slf4j和slf4j-log4j12同时存在会循环依赖栈溢出,需要排除--> <!-- <dependency>--> <!-- <groupId>org.slf4j</groupId>--> <!-- <artifactId>log4j-over-slf4j</artifactId>--> <!-- <version>1.7.25</version>--> <!-- </dependency>-->
集成log4j2
<!-- log4j2的两个API包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.9.1</version> </dependency> <!-- slf4j的API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包: slf4j转向log4j2 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency> <!-- 适配包: log4j2转向slf4j --> <!-- log4j-to-slf4j和log4j-slf4j-impl同时存在会循环依赖栈溢出,需要排除--> <!-- <dependency>--> <!-- <groupId>org.apache.logging.log4j</groupId>--> <!-- <artifactId>log4j-to-slf4j</artifactId>--> <!-- <version>2.9.1</version>--> <!-- </dependency>-->
集成logback
<!-- slf4j的API包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- logback的两个API包--> <!-- logback的Log相关API和包路径和slf4j一样,所以logback可以看作是slf4j的默认实现包--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
集成JCL
<!-- jul默认是JCL默认的实现包,也可以指定为log4j/log4j2 --> <!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <!-- slf4j的API包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包: slf4j转向jcl --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jcl</artifactId> <version>1.7.25</version> </dependency> <!-- jcl-over-slf4j和slf4j-jcl同时存在会循环依赖栈溢出,需要排除--> <!-- 适配包: jcl转向slf4j --> <!-- <dependency>--> <!-- <groupId>org.slf4j</groupId>--> <!-- <artifactId>jcl-over-slf4j</artifactId>--> <!-- <version>1.7.25</version>--> <!-- </dependency>-->
2.3.2.2 slf4j整合混合框架
slf4j获取具体框架的流程如下,可得知slf4j最终只能转向单个日志框架。
LoggerFactory.getLogger触发初始化
-> 根据classLoader查找org/slf4j/impl/StaticLoggerBinder.class,check不能有多个
-> 触发org.slf4j.impl.StaticLoggerBinder(不同集成框架路径相同实现不同)的getBean初始化
-> 报告StaticLoggerBinder的实际采用
-> slf4j版本检验
-> 根据StaticLoggerBinder获取org.slf4j.ILoggerFactory
-> 根据ILoggerFactory获取到org.slf4j.Logger
两个或以上的日志框架使用时,需要整合。达到以下目标:
- 全部日志API生效,能正常输出日志
- 排除冲突,避免循环转换栈溢出
- 排除冲突,避免slf4j转向实现框架
根据最终转向的日志框架分类:
最终整合为jul
最终整合为log4j
最终整合为log4j2
最终整合为logback
三、总结
3.1 所有相关包
3.1.1 核心日志框架包
<!-- log4j的API包 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- log4j2的两个API包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.9.1</version> </dependency> <!-- logback的两个API包--> <!-- logback的Log相关API和包路径和slf4j一样,所以logback可以看作是slf4j的默认实现包--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
3.1.2 门面日志框架
<!-- slf4j的API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <!-- jcl的API包 --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency>
3.1.3 适配包
<!-- 适配包:slf4j转向jul --> <!-- jul-to-slf4j和slf4j-jdk14包同时存在会造成jul和slf4j循环转化,所以要排除 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:jul转向slf4j --> <!-- jul-to-slf4j和slf4j-jdk14包同时存在会造成jul和slf4j循环转化,所以要排除 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:slf4j转向log4j --> <!-- log4j-over-slf4j和slf4j-log4j12同时存在会循环依赖栈溢出,需要排除--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:log4j转向slf4j --> <!-- log4j-over-slf4j和slf4j-log4j12同时存在会循环依赖栈溢出,需要排除--> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包: slf4j转向log4j2 --> <!-- log4j-to-slf4j和log4j-slf4j-impl同时存在会循环依赖栈溢出,需要排除--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency> <!-- 适配包: log4j2转向slf4j --> <!-- log4j-to-slf4j和log4j-slf4j-impl同时存在会循环依赖栈溢出,需要排除--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.9.1</version> </dependency> <!-- 适配包: slf4j转向jcl --> <!-- jcl-over-slf4j和slf4j-jcl同时存在会循环依赖栈溢出,需要排除--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jcl</artifactId> <version>1.7.25</version> </dependency> <!-- jcl-over-slf4j和slf4j-jcl同时存在会循环依赖栈溢出,需要排除--> <!-- 适配包: jcl转向slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <!-- 适配包:jcl转向log4j2 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>2.9.1</version> </dependency>
3.2 依赖冲突解决总结
双向适配包循环依赖
slf4j-jdk14和jul-to-slf4j(运行时直接栈溢出)
slf4j-log4j12和log4j-over-slf4j(启动会检测报错)
log4j-slf4j-impl和log4j-to-slf4j(运行时直接栈溢出)
slf4j-jcl和jcl-over-slf4j(启动会检测报错)
slf4j单个实现类
使用slf4j整合其他框架时,只能转向单个日志框架,即class路径只能有一个org.slf4j.impl.StaticLoggerBinder
因此以下包不能同时使用,只能出现一个:
slf4j-jdk14
slf4j-log4j12
log4j-slf4j-impl
logback-classic
slf4j-jcl
其他冲突
比如:
log4j.jar 低版本的和高版本冲突:目前测试下来:log4j1.2.6和1.2.17 两个jar同时引入导致日志不能打印
到此这篇关于java中log使用小结的文章就介绍到这了,更多相关java log使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot整合SpringSession实现分布式登录详情
这篇文章主要介绍了SpringBoot整合SpringSession实现分布式登录详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下2022-08-08springboot接口如何多次获取request中的body内容
这篇文章主要介绍了springboot接口多次获取request中的body内容的过程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-06-06自定义注解实现Spring容器注入Bean方式(类似于mybatis的@MapperScans)
本文介绍了如何通过自定义注解@MyService和@MyServiceScans在SpringBoot项目中自动将指定包下的类注入Spring容器,详细解释了创建自定义注解、定义包扫描器ClassPathBeanDefinitionScanner的作用与实现2024-09-09
最新评论