日志系列:
日志那点事儿(一)-基础介绍:https://mp.csdn.net/postedit/99835884
废话不多说,先来张大合照~~~~~
与日志相关的开源框架有很多,那么怎么应用它们?怎么用好它们?它们的特点是什么?下面,我讲大概介绍一下这些日志框架。
一、日志门面框架
所谓门面,就是它不实现具体的日志打印,参考设计模式的门面模式,它只是提供了接口。需要配合真正的日志实现框架才能打印日志。这样做的好处是:如果直接绑定日志实现框架,那么在切换的时候会带来大量的修改工作。引入门面日志框架,可以实现程序的解耦,对于底层日志框架的改变,并不会影响上层业务代码
名称 | 实现结构 | maven依赖 | 其他 |
slf4j | 对比CommonsLogging,它在编译时确定底层的日志实现框架,而不是通过配置文件动态地装载底层的实现类,因此只要底层的日志实现jar包和slf4j的静态编译转移包在类路径下即可 | <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> | 在使用方面最大的改进是增加了参数化日志在打印复杂日志的时候不再需要判断相应级别是否已打开 |
Commons Logging(JCL) | 一共两个包:org.apache.commons.logging和org.apache.commons.logging.impl 前者是日志api,后者是日志api的实现。它的使用无须在maven里引入单独的日志实现框架,便可在运行时直接转接底层的日志框架。。它通过查找commons-logging.properties根据里面配置加载日志实现框架,若找不到,通过反射api判断log4j是否存在于类路径中,如果不存在,则判断JDK14Logger是否在,若也不在,则使用内部简单的SimpleLog | <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> | 通过配置来动态找到具体的实现类,如果具体的实现类不在类路径中或被限制,则无法加载。例如在OSGI环境下类被分组后,就可能加载不到底层实现类 |
只使用slf4j不添加任何日志实现框架:
只使用apache commons logging不添加任何日志实现框架:
二、日志实现框架
日志实现框架是真正用来打印日志的框架。日志门面框架和日志实现框架绑定后,便可以打印日志,只有日志门面框架无法实现日志的输出。(特指slf4j,commons Longging比较特殊,它有自己的日志实现。现在开发大都用的是slf4j)。
名称 | 实现结构 | maven依赖 | 其他 |
JDK logger(JUL) | JDK从1.4版本起开始自带一套日志系统JDK Logger,它的优点就是不需要集成任何类库,只要有jvm运行环境就可以使用。使用起来很方便。但是这个框架可谓鸡肋,在易用性、功能以及扩展性方面都要稍逊一筹,很少在线上系统使用 | ||
log4j | 它的实现类主要包括三部分: 1、Logger:日志对象,负责捕捉日志记录的信息 2、Appender:日志输出目的地,负责把格式化的日志输出到指定的地方,可以是控制台、磁盘文件等 3、layout:对日志进行格式化,负责生成不同格式的日志信息,每个Appender对象对应一个Layout对象
| <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> | Java编写的可靠的、灵活的日志框架。Log4j默认的Appender使用的同步锁来实现的,当多个线程同时使用一个Logger时,在Category层次上加了同步锁。多个线程同时使用一个Appender的时候,在Appender层次上加了同步锁。所以log4j实现的日志在并发高、量大的时候会导致服务的性能下降。 |
logback | Logback分为三个模块: 1、logback-core:是基础模块,包含日志框架实现的所有基础类 2、logback-classic:是log4j的改良版本,在性能上有较大的提高,并且完整的实现了slf4j api 3、logback-access:与Servlet容器集成,提高了丰富的HTTP访问日志功能 | <dependency> <dependency> | 对log4j的内核进行了重写,在一些关键执行路径上性能提升了至少10倍,初始化内存加载也变得更小。同步记录日志可以达到1.5万/s |
log4j2 | log4j的升级版本,相对log4j有很多层面的提高,并且提高了logback的所有高级特性 log4j2实现了API模块和实现模块的分离。包含两个jar: 1、log4j-api:提供Log4j对我提供的API 2、log4j-core:实现日志记录功能的核心基础类 | <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.11.0</version> </dependency> | log4j2 的异步记录日志功能通过一个单独检查里执行I/O操作来提高性能,异步Logger是log4j2新引入的功能,使用无锁的Disruptor RingBuffer来实现 |
log4j、log4j2、logback性能比较:
使用log4j2打印日志:
三、日志绑定框架
日志门面框架想要用某个日志实现框架来打印日志就需要日志绑定框架。比如你的日志是使用slf4j实现的。如果你想要使用log4j实现的,你只要引入log4j的依赖和slf4j与log4j的绑定包,将他们两个绑在一起,那么项目就可以使用log4j打印日志。如果你想要slf4j使用log4j2打印日志,则引入log4j2的依赖和slf4j与log4j2的绑定包,将他们两个绑在一起,那么项目就可以使用log4j2打印日志。
(1)、slf4j使用log4j输出日志:
<!--slf4j依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--log4j依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--log4j与slf4j绑定依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
(2)、slf4j使用log4j2输出日志:
<!--slf4j依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!--log4j2核心依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<!--slf4j与log4j2绑定依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.0</version>
<scope>test</scope>
</dependency>
总结:slf4j自己是打印不出日志的。log4j、log4j2可以打印日志,但是项目就邦死log4j或log4j2了。slf4j配合日志实现就灵活很多。api使用slf4j。想用哪个日志框架输出,就加入相应的依赖。代码上不需要做出什么更改。
特别提示:我们经常会遇到一个问题,那就是依赖冲突问题
四、门面转换
门面转换就是,你本来使用的commons logging作为门面,但是现在你觉得slf4j比较流行,于是乎你想要转化为slf4j。可以借助门面转换框架进行转化
五、实现框架转slf4j
假设你有个项目本来使用的是log4j实现的日志。老天爷!你邦死在log4j上了,但是你又不想、不能、不敢更改代码。不要恐慌,你可以将log4j转换到slf4j上,然后再引入相应依赖,转换为使用log4j2或者logback实现。转到slf4j上,你还怕啥(^_−)☆
<!--log4j依赖 去掉log4j-->
<!-- <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>-->
<!--log4j->转到slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<!--slf4j依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
特别提示:依赖循环问题:
参考书籍:《分布式服务架构 原理、设计与实战》