SLF4J(Simple logging Facade for Java)
|
|-把不同的日志系统的实现进行了抽象,只提供了统一的日志使用接口,具体实现有log4j,logback,java.util.logging等;
|
|-为什么要使用SLF4J|--将调用和具体的日志实现分离,使用slf4j后有利于根据自己实际的需求更换具体的日志系统(模块移植的时候:比如复制一个通用的系统监控模块)
| |
| |--比如,之前使用的具体的日志系统为log4j,想更换为logback时,只需要删除log4j相关的jar,然后加入logback相关的jar和日志配置文件即可
| |--如果没有采用这种方式,当你的系统中日志输出有成千上万条时,你要更换日志系统将是多么庞大的一项工程
| |--如果你开发的是一个面向公众使用的组件或公共服务模块,
| | 那么一定要使用slf4的这种形式,这有利于别人在调用你的模块时保持和他系统中使用统一的日志输出
SLF4J集成图
SLF4J bound to logback-classic SLF4J bound to log4j SLF4J bound to java.util.logging SLF4J bound to simple SLF4J bound to no-operation
_______________________ _______________________ _______________________ _______________________ _______________________
| | | | | | | | | |
| Application | | Application | | Application | | Application | | Application |
| | | | | | | | | | | | | | |
| | | | | | | | | | | | | | |
| \|/ | | \|/ | | \|/ | | \|/ | | \|/ |
| slf4j-api.jar | | slf4j-api.jar | | slf4j-api.jar | | slf4j-api.jar | | slf4j-api.jar |
|_______________________| |_______________________| |_______________________| |_______________________| |_______________________|
| | | | |
_________\|/__________ \|/ \|/ _________\|/__________ _________\|/___________
| | ___Adaptation layer____ ___Adaptation layer____ | | | |
| logback-classic.jar | | | | | | slf4j-simple.jar | | slf4j-nop.jar |
| logback-core.jar | | slf4j-log4j12.jar | | slf4j-jdk14.jar | |_______________________| |_______________________|
|_______________________| |_______________________| |_______________________|
_________\|/___________ _________\|/___________
| | | |
| log4j.jar | | java.util.logging.* |
|_______________________| |_______________________|
Slf4j实现机制决定Slf4j限制较少,使用范围更广。由于Slf4j在编译期间,静态绑定本地的LOG库使得通用性要比Commons logging要好。
Logback和Log4j对比
Logback拥有更好的性能。Logback声称:某些关键操作,其性能得到了显著的提高。
比如:
判定是否记录一条日志语句的操作|--Logback中需要3纳秒
|--Log4J中则需要30纳秒
创建记录器(logger)的操作 |--Logback中需要13毫秒
|--Log4J中则需要23毫秒
获取已存在的记录器的操作 |--Logback中需要94纳秒
|--Log4J需要2234纳秒
文档方面 |--Logback的所有文档是全面免费提供的
|--Log4J只提供部分免费文档而需要用户去购买付费文档
SLF4J常见问题
1.什么时候需要使用SLF4J?
|
|--1.通用模块,我们不能限制用户使用那个日志框架
|--2.应用可能会在交付后改变技术选型时,最好使用SLF4J(SLF4J API is backward compatible for all versions)
|
|--3.单机应用,且技术选型不会改变的场景,可以不使用SLF4J
2.高效log方式的最佳实践。
|
|-将日志信息参数化|-- Object entry = new SomeObject();
| |-- logger.debug("The entry is {}.", entry);
|
|-两种不高效的写法|--1.logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
| | 缺点:不管记不记录,都会做字符串拼接;
| |--2.if(logger.isDebugEnabled()) {
| | logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
| | }
| | 缺点:做了两次重复的校验(校验是否要记录);
3.没有Fatal level的API可以记录Fatal的日志吗?
|
|--可以在error API中使用org.slf4j.Marker来标记
|
|--import org.slf4j.Logger;
|--import org.slf4j.LoggerFactory;
|--import org.slf4j.Marker;
|--import org.slf4j.MarkerFactory;
|
|--class Bar {
|-- void foo() {
|-- Marker fatalMarker = MarkerFactory.getMarker("FATAL");
|-- Logger logger = LoggerFactory.getLogger("aLogger");
|--
|-- try {
|-- // obtain a JDBC connection
|-- } catch (JDBException e) {
|-- logger.error(fatalMarker, "Failed to obtain JDBC connection", e);
|-- }
|-- }
|--}