列举下市场中常见的一些log方案,
- log4j
- log4j2
- jcl
- jul
- slf4j
- logback
说一下它们之间的关系,log4j2是log4j的升级版,对标logback,提升性能以及日志格式的一些支持。 jul全称java.util.logging,可见是jdk中提供的日志方案, jcl全称org.apache.commons.logging,spring底层使用的就是jcl,但是在spring4和spring5中有一些区别,下文会说明。 sfl4j和jcl一样,它本身是不打印log的,而是去适配项目中引用了哪种日志方案。简单的通过源码和代码来验证。
先看jcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Log getLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jDelegate.createLog(name);
case SLF4J_LAL:
return Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return Slf4jDelegate.createLog(name);
default:
// Defensively use lazy-initializing delegate class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilDelegate.createLog(name);
}
}
可见当项目中引用log4j的时候就会使用log4j去打印日志,最后默认使用java.util.logging即jul。
slf4j的官网上给了两页简单的使用手册, 当项目引入slf4j的时候,不仅要引入自身的包,还需要引入binder,否则会提示 Failed to load class “org.slf4j.impl.StaticLoggerBinder”
官网给出的binder列表如下:
- slf4j-log4j12-1.8.0-beta4.jar
- slf4j-jdk14-1.8.0-beta4.jar
- slf4j-nop-1.8.0-beta4.jar
- slf4j-simple-1.8.0-beta4.jar
- slf4j-jcl-1.8.0-beta4.jar
- logback-classic-1.0.13.jar (requires logback-core-1.0.13.jar)
需要根据自己引入的slf4j版本来选择binder的版本,否则日志会有问题, 另外如果引入多种binder会提示SLF4J: Class path contains multiple SLF4J bindings.
另外slf4j提供了桥接模块,即当我们的项目的日志方案与项目中引用框架的日志方案不一样的时候,
可以通过桥接统一使用slf4j的日志方案,然后通过slf4j的binder来实现统一的日志处理。
下面是官网给出的一张桥接的图。
最后补充下spring5中的日志实现,spring5中日志实现默认是jul, 会去自动的使用项目引用的日志方案,具体实现如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private static LogApi logApi = LogApi.JUL;
public static Log getLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jDelegate.createLog(name);
case SLF4J_LAL:
return Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return Slf4jDelegate.createLog(name);
default:
// Defensively use lazy-initializing delegate class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
return JavaUtilDelegate.createLog(name);
}
}