SLF4J 用户使用手册
SLF4J是Simple Logging Facade For Java的缩写,从名字中的Facade可以看出它是一个门面。SLF4J并不是一个具体实现,而是一个日志框架,或者说日志框架的抽象,可以在程序运行时,更新Classpath中的jar包加载具体的日志实现,比如说log4j、logback。这个具体的实现可以称之为binding
SINCE 1.6.0
如果没有在classpath中发现binding,那么SLF4J不会做任何操作
SINCE 1.7.0
接口Logger支持接受多种参数的方法,以替代Object[],它需要只是JDK1.5以上的版本。多种参数变量将在Java编译器后台被装换成object[],因此编译器生成的接口在1.7x 和1.6.x中是无法区分的,因此1.7.x是完全100%兼容1.6.x的。
SINCE 1.7.5
日志索引时间得到了显著的提升,建议用户使用SLF4J 至少1.7.5以后的版本。
SINCE 1.7.9
通过将slf4j.detectLoggerNameMismatch系统属性设置为true,SLF4J可以自动发现名称错误的记录器。
SINCE 2.0.0
SLF4J 2.0.0 API依赖了JDK8,并且提供了向后兼容的流式API。因为向后兼容性,所以现有的日志框架不需要做任何修改就可以实现使用流式API了。
Hello World
按照编程传统,下面是一个使用SLF4J输出“Hello World”的最简代码段。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
编译、运行HelloWorld将在控制台输出以下内容。
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
上面的warning,说明了没有在classpath中找到slf4j binding,将slf4j-simple-1.7.28.jar加入classpath中即可输出如下的正确结果
0 [main] INFO HelloWorld - Hello World
典型的使用模式
下面的代码展示了SLF4J典型的使用模式。注意第15行占位符{}
的使用方式。请尽量使用占位符的方式来代替字符串拼接,这样可以避免多余的计算,显著提高框架的性能。
1: import org.slf4j.Logger;
2: import org.slf4j.LoggerFactory;
3:
4: public class Wombat {
5:
6: final Logger logger = LoggerFactory.getLogger(Wombat.class);
7: Integer t;
8: Integer oldT;
9:
10: public void setTemperature(Integer temperature) {
11:
12: oldT = t;
13: t = temperature;
14:
15: logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);
16:
17: if(temperature.intValue() > 50) {
18: logger.info("Temperature has risen above 50 degrees.");
19: }
20: }
21: }
流式API
这个想法是使用LoggingEventBuilder逐段构建日志事件,并在事件完全构建后进行日志记录。atTrace()
,atInfo()
,atWarn()
和atError()
方法都是org.slf4j.Logger接口中的新方法,它将返回一个LogginEventBuilder,在disable级别的日志level,这个方法不会做任何的事情,这是一个纳秒级别的优化。
下面是一些用法示例:
logger.atInfo().log("Hello world");
// 等同于
logger.info("Hello world.");
下面的语句在功能上等同与以前接口
int newT = 15;
int oldT = 16;
// using traditional API
logger.debug("Temperature set to {}. Old temperature was {}.", newT, oldT);
// using fluent API, add arguments one by one and then log message
logger.atDebug().addArgument(newT).addArgument(oldT).log("Temperature set to {}. Old temperature was {}.");
// using fluent API, log message with arguments
logger.atDebug().log("Temperature set to {}. Old temperature was {}.", newT, oldT);
// using fluent API, add one argument and then log message providing one more argument
logger.atDebug().addArgument(newT).log("Temperature set to {}. Old temperature was {}.", oldT);
// using fluent API, add one argument with a Supplier and then log message with one more argument.
// Assume the method t16() returns 16.
logger.atDebug().addArgument(() -> t16()).log(msg, "Temperature set to {}. Old temperature was {}.", oldT);
在部署的时候绑定日志实现框架
前面提到了SLF4J支持多种日志框架,在SLF4J发布的时候,会一起发布多种SLF4J binding jar,每一种binding都可以实现SLF4J到一个具体日志实现的绑定。
- slf4j-log4j12-1.7.28.jar:绑定了log4j 1.2
- slf4j-jdk14-1.7.28.jar: 绑定了JDK1.4的java.util.logging
- slf4j-nop-1.7.28.jar: 绑定了NOP
- slf4j-simple-1.7.28.jar: 绑定了一个Simple实现,它将所有事件输出到System.err,只有INFO以及其INFO级别以上的信息将被打印。
- slf4j-jcl-1.7.28.jar:绑定了 Jakarta Common Logging
- logback-classic-1.2.3.jar: 需要logback-core-1.2.3.jar,Logback直接的的实现了SLF4j的接口org.slf4j.Logger,因此,结合使用SLF4J和logback会涉及严格的零内存和计算开销。
如果要切换日志实现框架,只需要替换classpath中的slf4j binding即可。例如:将java.util.logging 换为log4j,需要将slf4j-jdk14-1.7.28.jar替换为slf4j-log4j12-1.7.28.jar。
SLF4J在编译期间执行了硬链接,运行期间只有一种日志实现框架能够被使用,所以不要在classpath中放入多种binding SLF4J接口和各种adapter代码实现都非常简单,大多数熟悉Java代码的开发人员都能够在1小时能阅读并理解源码。同时,阅读SLF4J源码也不需要了解类加载器,因为SLF4J没有直接使用类加载器,所以SLF4J不会遇到累加器的问题,也不会遇到Jakarta Commons Logging中内存泄露问题。
根据上面的SLF4J接口和模型,开发人员应该很实现一个SLF4J binding。
类库
类库和组件的作者应该针对SLF4J接口进行编码,这样终端用户就可以通过classpath中的jar包,选择自己的需要选择日志框架。这是一种简单并且行之有效的办法。
基本规则:内嵌式的组件、类库应该避免声明依赖任何SLF4J binding,仅仅依赖slf4j-api就够了。
为Logging声明项目依赖
LOGBACK-CLASSES
如果你使用loback-classic作为底层日志框架,你只需要像下面示例代码一样,在pom.xml中声明就可以了,它会将logback-core-1.2.3.jar以及slf4j-api-1.7.28.jar都添加到项目中。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
LOG4J
如果你想要使用log4j作为底层日志框架实现,那么你需要在pom.xml中声明"org.slf4j:slf4j-log4j12-1.7.28.jar"就可以了。他将引入slf4j-log4j12-1.7.28.jar, slf4j-api-1.7.28.jar log4j-1.2.17.jar 到你的项目中。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
</dependency>
兼容性
从客户的角度来讲,所有版本的slf4j-api都是兼容的。slf4j-api-N能够和slf4j-api-M完全的兼容,因此不需要担心有太多slf4j-api的依赖。 但是一定需要关注和保证binding。 binding需要和slf4j-api匹配。
通过slf4j合并日志
有时候,你的工程依赖了各种不同的组件,而这些组件并没有使用slf4j,可能是common log、log4j等。slf4j为提供了bridging解决这种场景
posted on 2020-02-23 12:01 yipianlarou 阅读(706) 评论(0) 编辑 收藏 举报