概述
在软件开发中,日志无处不在。选择一个好的日志框架,要关注其使用起来的可读性、高性能、开发效率、是否简洁易上手、功能完备、社区的活跃度等等。这里我将单独梳理一下在 Java 中的日志框架体系,这套体系如果不去仔细梳理一番,乍一看会感觉非常混乱,尤其是一些早期的 jar 包命名,很有迷惑性。不过只要仔细梳理过一遍,就会发现,它们的作用和边界其实是很清晰的。不用刻意去记,只需理解,等遇到时,当成手册查一查即可。
基本概念
在梳理之前,我们需要先了解一些背景和概念:
- **日志实现:**具有完整的输出日志的能力,可以独立使用。
- **日志门面:**统一了日志输出接口,屏蔽了各种日志实现的用法差异。必须搭配一个日志实现才能正常使用,无法独立使用。在项目开发中,都应该使用这种方式打日志。
- **门面适配实现:**使用门面打日志时,如何将日志重定向到那些实现进行输出?只需针对不同的门面和实现引入对应的适配器即可。
- 实现桥接门面:在一个应用中,依赖的 jar 里面如果使用了其它实现打日志,如何重定向到自己的实现里?这就需要现将先其重定向到一个门面上,再通过门面适配到自己的实现里,这个过程叫做桥接,只需针对不同的实现和门面引入对应的桥接器即可。
- **时间线:**先看看日志实现/门面出场的时间线,Log4j -> JUL -> JCL -> SLF4J -> Logback -> Log4j2(推荐) -> Reload4j(Log4j 替代品) -> SLF4J2(推荐)
- **缩写的含义:**JUL 就是 Java Util Loging,JCL 就是 Jakarta Commons Logging
- **循环重定向问题:**A 门面适配到 B 实现,然后 B 实现又桥接到 A 门面,这种搭配是不行的,会报错。
- **民间俗称:**SLF4J 是酸辣粉?从哪传出来的,不得而知。
日志实现
名称 | 依赖坐标 | 备注 |
---|---|---|
log4j 实现 | log4j:log4j | 不建议使用了 |
log4j 实现(老版) | org.apache.log4j:org.apache.log4j | 已废弃 |
log4j 实现(springsource 版) | org.apache.log4j:com.springsource.org.apache.log4j | 已废弃 |
reload4j 实现(替代 log4j 的) | ch.qos.reload4j:reload4j | 不建议使用了 |
logback 实现 | ch.qos.logback:logback-core | |
log4j2 实现 | org.apache.logging.log4j:log4j-core | 推荐 |
jdk 实现 | jdk 自带,非第三方 | 简称 jul,即 java.util.logging |
slf4j-simple | org.slf4j:slf4j-simple | SLF4J 提供的基本日志实现,几乎用不到 |
注意:
- 按照编码规约建议,都应该使用 log4j2,其它日志实现都应该排除掉。
- log4j2 如果要开启异步特性,即使用 AsyncLogger,必须引入 disruptor 包,依赖坐标是:com.lmax:disruptor
日志门面
名称 | 依赖坐标 | 备注 |
---|---|---|
slf4j 门面 | org.slf4j:slf4j-api | 推荐,目前 2.x 版本已经正式发布 |
jcl 门面 | commons-logging:commons-logging | |
jcl 门面(老版) | commons-logging:commons-logging-api | 已废弃 |
jcl 门面(spring 版) | org.springframework:spring-jcl | spring 框架用于兜底的,如果明确引入了对 jcl 的桥接包,则可以排除 |
log4j2 门面 | org.apache.logging.log4j:log4j-api | 其实现就是 log4j-core |
注意:
- 按照编码规约建议,打日志都应该使用 SLF4J 的 API,并适配到 log4j2 实现。
- 以上 jcl 门面是默认自带适配逻辑的,会自动适配到 log4j/log4j2-api/slf4j/jul 其中之一,不太可控,所以我们一般会引入其它门面对 jcl 的桥接包,让 jcl 桥接到其它门面下(slf4j 或 log4j2-api)。
SLF4J 的适配器(slf4j -> xxx)
适配方向 | 依赖坐标 | 备注 |
---|---|---|
slf4j -> log4j | org.slf4j:slf4j-log4j12 | |
slf4j -> reload4j | org.slf4j:slf4j-reload4j | |
slf4j -> logback | ch.qos.logback:logback-classic | |
slf4j -> log4j2 | org.apache.logging.log4j:log4j-slf4j-impl | 推荐 |
slf4j2 -> log4j2 | org.apache.logging.log4j:log4j-slf4j2-impl | 推荐,最新的 slf4j2 !!! |
slf4j -> jcl | org.slf4j:slf4j-jcl | |
slf4j -> jul | org.slf4j:slf4j-jdk14 |
注意:以上适配依赖在运行时只能出现一个,其它都要排除掉,否则会产生 SLF4J 多实现绑定的警告,并且会选择其中一个实现,不可控。
SLF4J 的桥接器(xxx -> slf4j)
桥接方向 | 依赖坐标 | 备注 |
---|---|---|
log4j -> slf4j | org.slf4j:log4j-over-slf4j | |
log4j2 -> slf4j | org.apache.logging.log4j:log4j-to-slf4j | |
jcl -> slf4j | org.slf4j:slf4j-jcl | 不推荐,推荐使用:jcl -> log4j-api |
jcl -> slf4j(老版) | org.slf4j:jcl104-over-slf4j | 已废弃 |
jul -> slf4j | org.slf4j:jul-to-slf4j | 不推荐,推荐使用:jul -> log4j-api |
Log4j2 门面的桥接器(xxx -> log4j-api)
桥接方向 | 依赖坐标 | 备注 |
---|---|---|
log4j -> log4j2-api | org.apache.logging.log4j:log4j-1.2-api | |
jcl -> log4j2-api | org.apache.logging.log4j:log4j-jcl | 推荐 |
jul -> log4j2-api | org.apache.logging.log4j:log4j-jul | 推荐 |
最佳实践(使用 Log4j2)
以上列出的所有依赖,只要不在以下这个列表里的,都可以排除了。
<!--#region 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!--采用log4j2实现-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
</dependency>
<!--slf4j 适配到 log4j2实现-->
<dependency>
<groupId>com.alipay.org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<!-- jcl 桥接到 log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
</dependency>
<!-- jul 桥接到 log4j2 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jul</artifactId>
</dependency>
<!-- log4j1.x 桥接到 log4j2 -->
<dependency>
<groupId>com.alipay.org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
</dependency>
<!--#endregion 日志 -->
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于