- 什么是slf4j?
slf4j可以作为各种日志框架简单的外观或抽象,它提供了一套标准的、统一的日志操作API,事实上它只提供操作日志的门面(接口)并未提供具体的实现方案;
所以我们对slf4j正确的理解是:对于slf4j的使用,必须依赖于一个具体的实现,那么这些具体的实现都有哪些?请参考后文《slf4j绑定具体实现》;
注意:一个以slf4j作为日志操作入口的工程项目需要控制slf4j绑定的实现方式只有一种,因为多个实现并存的情况下,有一定几率导致日志功能失效。 - slf4j都能绑定哪些常用的开源日志框架呢?
logback(天然支持slf4j,logback所有日志操作都基于slf4j提供的接口);
log4j2(log4j2自身提供接口参见:org.apache.logging.log4j.Logger);
log4j(log4j自身提供接口参见:org.apache.log4j.Logger)。 - slf4j绑定上这几种常用的开源日志框架是否需要额外的依赖来实现?
logback,因为纯天然支持slf4j,所以只需要引入logback相关的jar就可以直接使用slf4j提供的原生接口进行日志操作;
log4j2,需要额外添加jar包 log4j-slf4j-impl,作用是:通过org.apache.logging.log4j.Logger 操作日志和slf4j-api操作日志,效果相同;
log4j,需要额外添加jar包slf4j-log4j12, 作用是:通过org.apache.log4j.Logger操作日志和slf4j-api操作日志,效果相同。 - 其他额外的需求?
我们有将slf4j绑定上具体实现的需求,是否也存在将某些日志框架的日志桥接到slf4j的需求呢?
答案是,有的。接下来我将列举几个需要桥接日志的场景 ;
a、假设我们项目用slf4j绑定log4j实现(已有jars:slf4j-api、slf4j-log4j12),现在有需求需要将log4j升级为log4j2,应该怎么处理?
[[a场景解决方案:1.添加log4j2相关jar包log4j-core;2.添加 log4j-slf4j-impl 用以实现slf4j;3.去掉 slf4j-log4j12 保证slf4j实现唯一 ;4.log4j-over-slf4j 替换原log4j,可以将原来通过log4j接口记录的日志自动桥接到slf4j接口上去 ]]
b、我们项目基于spring构建,spring大量使用commons-logging,我该如何将这部分日志桥接至slf4j呢?
[[b场景解决方案:1.jar包jcl-over-slf4j 替换原commons-logging,可以将原通过commons-logging接口记的日志自动桥接到slf4j接口上去 ]]
- slf4j 的双向性
向下绑定具体实现:我们可以通过额外的jar保证slf4j接口绑定上某个具体的开源日志框架;
向上桥接其他接口日志:也可以选择一些jars替换原开源日志框架的jars,将该日志框架操作的日志,桥接到slf4j接口上来;
绑定实现的实际变化过程是:通过[[slf4j接口]]操作的日志最终会导入到[[XX日志框架接口]];
桥接其他日志的实际变化过程是:通过[[XX日志框架接口]]操作的日志最终会导入到[[slf4j接口]]。
slf4j绑定具体实现
1、logback
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
demo code:
import org.slf4j.LoggerFactory;
public class LogDemo {
private static org.slf4j.Logger SLF4J_API = LoggerFactory.getLogger(LogDemo.class);
/**
* @param args
*/
public static void main(String[] args) {
// 记录debug级别的信息
SLF4J_API.debug("This is debug message by slf4j api");
// 记录info级别的信息
SLF4J_API.info("This is info message by slf4j api");
// 记录error级别的信息
SLF4J_API.error("This is error message by slf4j api");
}
}
2、log4j2
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
</dependencies>
demo code:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 此项目是log4j2 日志配置项目
* 配置文件见 log4j2.xml
*
* log4j2是log4j的升级版
*
* log4j的api见 org.apache.log4j.Logger
* log4j2的api见 org.apache.logging.log4j.Logger
*
*/
public class Log4j2AndSlf4jUtil {
private static Logger LOG4J2_API = LogManager.getLogger(Log4j2AndSlf4jUtil.class);
private static org.slf4j.Logger SLF4J_API = LoggerFactory.getLogger(Log4j2AndSlf4jUtil.class);
/**
* @param args
*/
public static void main(String[] args) {
//此处LOG4J2_API 与 SLF4J_API 输出效果相同
// 记录debug级别的信息
LOG4J2_API.debug("This is debug message by log4j2 api");
// 记录info级别的信息
LOG4J2_API.info("This is info message by log4j2 api");
// 记录error级别的信息
LOG4J2_API.error("This is error message by log4j2 api");
// 记录debug级别的信息
SLF4J_API.debug("This is debug message by slf4j api");
// 记录info级别的信息
SLF4J_API.info("This is info message by slf4j api");
// 记录error级别的信息
SLF4J_API.error("This is error message by slf4j api");
}
}
3、log4j
<dependencies>
<!-- 祛除原log4j 并替换为log4j-over-slf4j-->
<!--<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>-->
<!-- 作用为,将log4j转到slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
</dependencies>
demo code:
import org.slf4j.LoggerFactory;
/**
* 此项目是log4j2 日志配置项目
* 配置文件见 log4j2.xml
*
* log4j2是log4j的升级版
*
* log4j的api见 org.apache.log4j.Logger
* log4j2的api见 org.apache.logging.log4j.Logger
*
*/
public class LogUtil {
private static org.slf4j.Logger SLF4J_API = LoggerFactory.getLogger(LogUtil.class);
private static org.apache.log4j.Logger LOG4J_API = org.apache.log4j.Logger.getLogger(LogUtil.class);
/**
* @param args
*/
public static void main(String[] args) {
//此处LOG4J_API 与 SLF4J_API 输出效果相同
//SLF4J_API 具体实现 请参考上文 Logback/log4j2实现
// 记录debug级别的信息
SLF4J_API.debug("This is debug message by slf4j api");
// 记录info级别的信息
SLF4J_API.info("This is info message by slf4j api");
// 记录error级别的信息
SLF4J_API.error("This is error message by slf4j api");
// 记录debug级别的信息
LOG4J_API.debug("This is debug message by log4j api");
// 记录info级别的信息
LOG4J_API.info("This is info message by log4j api");
// 记录error级别的信息
LOG4J_API.error("This is error message by log4j api");
}
}
4、commons-logging
<dependencies>
<!-- 祛除原commons-logging 并替换为jcl-over-slf4j-->
<!--<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>-->
<!-- 作用为,将commons-logging日志转到slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
</dependencies>
demo code:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.LoggerFactory;
public class LogUtil {
private static org.slf4j.Logger SLF4J_API = LoggerFactory.getLogger(LogUtil.class);
public static Log COMMON_LOG_API = LogFactory.getLog(LogUtil.class);
/**
* @param args
*/
public static void main(String[] args) {
//此处SLF4J_API 与 COMMON_LOG_API 输出效果相同
//SLF4J_API 具体实现 请参考上文 Logback/log4j2实现
SLF4J_API.debug("This is debug message by slf4j api");
SLF4J_API.info("This is info message by slf4j api");
SLF4J_API.error("This is error message by slf4j api");
COMMON_LOG_API.debug("This is debug message by common-log api");
COMMON_LOG_API.info("This is info message by common-log api");
COMMON_LOG_API.error("This is error message by common-log api");
}
}
日志框架注意事项
多个slf4j实现冲突
多个实现slf4j的jar引入的情况下,由于slf4j选择具体实现的方式带有一些随机性,可能会导致日志不能像预期一样输出!
slf4j可以选择以下jar包 绑定实现,正常maven dependencies下,以下jar包不应该并存,以保证slf4j实现是唯一的。
log4j-slf4j-impl
将slf4j接口的日志移交给log4j2
slf4j-log4j12-1.8.0-beta1.jar
Binding for log4j version 1.2, a widely used logging framework. You also need to place log4j.jar on your class path.
slf4j-jdk14-1.8.0-beta1.jar
Binding for java.util.logging, also referred to as JDK 1.4 logging
slf4j-nop-1.8.0-beta1.jar
Binding for NOP, silently discarding all logging.
slf4j-simple-1.8.0-beta1.jar
Binding for Simple implementation, which outputs all events to System.err. Only messages of level INFO and higher are printed. This binding may be useful in the context of small applications.
slf4j-jcl-1.8.0-beta1.jar
Binding for Jakarta Commons Logging. This binding will delegate all SLF4J logging to JCL.
logback-classic-1.0.13.jar (requires logback-core-1.0.13.jar)
Native implementation There are also SLF4J bindings external to the SLF4J project, e.g. logback which implements SLF4J natively. Logback's ch.qos.logback.classic.Logger class is a direct implementation of SLF4J's org.slf4j.Logger interface. Thus, using SLF4J in conjunction with logback involves strictly zero memory and computational overhead.
slf4j绑定XX实现和XX桥接至slf4j相关jar并存
比如我们项目中已经有slf4j绑定log4j实现的额外jar slf4j-log4j12 由于一些更新操作,工程又引入了新jar
log4j-api->log4j-over-slf4j->slf4j-api->slf4j-log4j12->log4j-api
两者的功能导致日志循环桥接迁移,类似这种jar包 在一个工程内应该严格保证不会有共存情况
将其他接口迁移到slf4j的几种情况:
jcl-over-slf4j.jar 【使用方法:替代commons-logging.jar】【jcl-over-slf4j.jar 与slf4j-jcl 冲突】
To ease migration to SLF4J from JCL, SLF4J distributions include the jar file jcl-over-slf4j.jar. This jar file is intended as a drop-in replacement for JCL version 1.1.1. It implements the public API of JCL but using SLF4J underneath, hence the name "JCL over SLF4J."
Our JCL over SLF4J implementation will allow you to migrate to SLF4J gradually, especially if some of the libraries your software depends on continue to use JCL for the foreseeable future. You can immediately enjoy the benefits of SLF4J's reliability and preserve backward compatibility at the same time. Just replace commons-logging.jar with jcl-over-slf4j.jar. Subsequently, the selection of the underlying logging framework will be done by SLF4J instead of JCL but without the class loader headaches plaguing JCL. The underlying logging framework can be any of the frameworks supported by SLF4J. Often times, replacing commons-logging.jar with jcl-over-slf4j.jar will immediately and permanently solve class loader issues related to commons logging.
log4j-over-slf4j【使用方法:替代log4j.jar】【log4j-over-slf4j.jar 与slf4j-log4j12 冲突】
SLF4J ship with a module called log4j-over-slf4j. It allows log4j users to migrate existing applications to SLF4J without changing a single line of code but simply by replacing the log4j.jar file with log4j-over-slf4j.jar, as described below.
jul-to-slf4j 【jul-to-slf4j .jar 与slf4j-jdk 冲突】
The jul-to-slf4j module includes a java.util.logging (jul) handler, namely SLF4JBridgeHandler, which routes all incoming jul records to the SLF4j API. Please see SLF4JBridgeHandler javadocs for usage instructions.

4万+

被折叠的 条评论
为什么被折叠?



