SLF4J是用于日志记录系统的简单外观,允许最终用户在部署时插入所需的日志记录系统。Simple Logging Facade for Java(SLF4J)用作各种日志框架(例如java.util.logging,logback,log4j)的简单外观或抽象,允许最终用户在部署 时插入所需的日志记录框架。
最简单的slf4j示例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
公共类HelloWorld {
public static void main(String [] args){
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info(“Hello World”);
}
要运行此示例,首先需要下载slf4j发行版,然后将其解压缩。完成后,将文件 slf4j-api-1.7.26.jar添加到类路径中。
https://www.slf4j.org/download.html
SLF4J只是一个外观,这意味着它不提供完整的日志记录解决方案。使用SLF4J无法执行配置appender或设置日志记录级别等操作。因此,在某个时间点,任何非平凡的应用程序都需要直接调用底层日志记录系统。换句话说,独立应用程序无法完全独立于API底层日志记录系统。然而,SLF4J减少了这种依赖对近乎无痛水平的影响。
假设您的CRM应用程序使用log4j进行日志记录。但是,您的一个重要客户端要求通过JDK 1.4日志记录执行日志记录。如果您的应用程序充斥着成千上万的直接log4j调用,那么迁移到JDK 1.4将是一个相对冗长且容易出错的过程。更糟糕的是,您可能需要维护两个版本的CRM软件。如果您一直在调用SLF4J API而不是log4j,则可以在几分钟内通过将一个jar文件替换为另一个jar文件来完成迁移。
官方提供的典型使用模式:
Fluent Logging API
自2.0.0以来, SLF4J API 2.0.0版需要Java 8,并引入了向后兼容的流畅日志API。我们的想法是与LoggingEventBuilder一起构建一个日志记录事件, 并在事件完全构建后记录。所有新的org.slf4j.Logger
界面,返回的一个实例LoggingEventBuilder
。对于禁用的日志级别,返回的 LoggingEventBuilder
实例不执行任何操作,从而保留常规日志记录接口的纳秒级性能。使用下列方法:
atTrace(),
atDebug(),
atInfo(),
atWarn(),
atError()
以下是一些使用示例:
int newT = 15;
int oldT = 16;
// using classical 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);
以下日志语句在其输出中是等效的(就默认实现而言):
int newT = 15;
int oldT = 16;
//使用经典API
logger.debug(“oldT = {} newT = {}温度已更改。”,newT,oldT);
//使用流畅的API
logger.atDebug()。addKeyValue(“oldT”,oldT) .addKeyValue(“newT”,newT).log(“Temperature changed。”);
SLF4J不依赖于任何特殊的类装载机械。实际上,每个SLF4J绑定在编译时都是硬连线的, 以使用一个且只有一个特定的日志记录框架。例如,slf4j-log4j12-1.7.26.jar绑定在编译时绑定以使用log4j。在您的代码中,除了slf4j-api-1.7.26.jar之外,您只需将 您选择的一个且只有一个绑定放到相应的类路径位置。不要在类路径上放置多个绑定。以下是一般概念的图解说明。
SLF4J接口及其各种适配器非常简单。大多数熟悉Java语言的开发人员应该能够在不到一小时的时间内阅读并完全理解代码。不需要类加载器的知识,因为SLF4J不能使用,也不能直接访问任何类加载器。因此,SLF4J不会遇到使用Jakarta Commons Logging(JCL)观察到的类加载器问题或内存泄漏。
鉴于SLF4J接口及其部署模型的简单性,新的日志框架的开发人员应该发现编写SLF4J绑定非常容易。
在SLF4J 1.0beta4中,修改了Logger接口中的debug(),info(),warn(),error()等打印方法,以便只接受String类型而不是Object类型的消息。
因此,DEBUG级别的打印方法集合变为:
debug (String msg );
debug (String format ,Object arg );
debug (String format ,Object arg1 ,Object arg2 );
debug (String msg ,Throwable t );
打印错误输出日志:
logger.error("some accompanying message", e);
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);
logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);
如何记录单个(可能是复杂的)对象的字符串内容?
在要记录的消息是对象的字符串形式的相对罕见的情况下,可以使用适当级别的参数化打印方法。假设complexObject
是一个具有某种复杂性的对象,对于级别DEBUG的日志语句,您可以编写:
logger.debug (“{}”,complexObject );
logger.debug (“{}”,complexObject );
complexObject.toString()
只有在确定启用了日志语句后,日志记录系统才会调用 方法。否则,complexObject.toString()
将有利地避免转换成本 。
如何使我的日志框架SLF4J兼容?
增加对SLF4J的支持非常简单。从本质上讲,你应对现有的绑定并稍微调整它(如下所述)就可以了。
假设您的日志记录系统具有记录器的概念,例如MyLogger,您需要提供适用MyLogger于 org.slf4j.Logger接口的适配器。有关适配器的示例,请参阅slf4j-jcl,slf4j-jdk14和slf4j-log4j12模块。
一旦编写了适当的适配器,比如说 MyLoggerAdapter,您需要提供一个实现该org.slf4j.ILoggerFactory 接口的工厂类。这个工厂应该返回实例 MyLoggerAdapter。让我们MyLoggerFactory 的工厂类名称。
一旦你有了适配器,即 MyLoggerAdapter和工厂,即 MyLoggerFactory最后剩下的一步是修改StaticLoggerBinder类,使它返回一个新的实例MyLoggerFactory。您还需要修改loggerFactoryClassStr变量。
对于Marker或MDC支持,您可以使用现有的NOP实现之一。
总之,要为日志记录系统创建SLF4J绑定,请按照下列步骤操作:
总之,将logger成员声明为静态变量需要较少的CPU时间并且内存占用量略小。另一方面,将记录器成员声明为实例变量需要更多的CPU时间并且具有稍高的内存开销。但是,实例变量可以为每个应用程序创建不同的记录器环境,即使对于在共享库中声明的记录器也是如此。也许比之前提到的考虑因素更重要的是,实例变量对IOC友好,而静态变量则不然。
声明用法:
package some.package;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
final (static) Logger logger = LoggerFactory.getLogger(MyClass.class);
... etc
}
参考文档:https://www.slf4j.org/