SLF4J - 快速指南

SLF4J - 概述

SLF4J 代表 Simple Logging Facade for Java。它提供了 Java 中所有日志框架的简单抽象。因此,它使用户能够使用单一依赖项使用任何日志框架,例如 Log4j、Logback 和 JUL (java.util.logging)。您可以在运行时/部署时迁移到所需的日志记录框架。

Ceki Gülcü 创建了 SLF4J 作为 Jakarta commons-logging 框架的替代方案。

Slf4j Api Jar

SLF4J 的优势

以下是 SLF4J 的优势 −

  • 使用 SLF4J 框架,您可以在部署时迁移到所需的日志记录框架。

  • Slf4J 提供与所有流行日志记录框架的绑定,例如 log4j、JUL、Simple logs 和 NOP。因此,您可以在部署时切换到任何这些流行的框架。

  • SLF4J 提供对参数化日志消息的支持,无论您使用哪种绑定。

  • 由于 SLF4J 将应用程序和日志框架分离,因此您可以轻松编写独立于日志框架的应用程序。您无需担心用于编写应用程序的日志框架。

  • SLF4J 提供了一个称为迁移器的简单 Java 工具。使用此工具,您可以将使用 Jakarta Commons Logging (JCL) 或 log4j 或 Java.util.logging (JUL) 等日志框架的现有项目迁移到 SLF4J。

SLF4J - 日志框架

编程中的日志是指记录活动/事件。通常,应用程序开发人员应该负责日志记录。

为了使日志记录工作更容易,Java 提供了各种框架 − log4J、java.util.logging (JUL)、tiny log、logback 等。

日志记录框架概述

日志记录框架通常包含三个元素 −

记录器

捕获消息以及元数据。

格式化程序

格式化记录器捕获的消息。

处理程序

处理程序或附加程序最终通过在控制台上打印、存储在数据库中或通过电子邮件发送来分发消息。

一些框架结合了记录器和附加程序元素以加快操作速度。

记录器对象

要记录消息,应用程序会发送一个记录器对象(有时还会发送异常,如果有的话),其中包含名称和安全级别。

严重性级别

记录的消息将具有各种级别。下表列出了日志记录的一般级别。

Sr.No 严重性级别 &描述
1

Fatal

导致应用程序终止的严重问题。

2

ERROR

运行时错误。

3

WARNING

在大多数情况下,错误是由于使用了弃用的 API 造成的。

4

INFO

发生在运行时。

5

DEBUG

有关系统流程的信息。

6

TRACE

有关系统流程的更多详细信息。

SLF4J 与 Log4j

什么是 log4j?

log4j 是一个可靠、快速且灵活的日志框架 (API),用 Java 编写,根据 Apache 软件许可分发。

log4j 在运行时可通过外部配置文件进行高度配置。它从优先级的角度来看待日志记录过程,并提供将日志记录信息定向到各种目标的机制,例如数据库、文件、控制台、UNIX Syslog 等。(有关 log4j 的更多详细信息,请参阅我们的教程)。

比较 SLF4J 和 Log4j

与 log4j 不同,SLF4J(Simple Logging Facade for Java)不是日志记录框架的实现,而是Java 中所有与 log4J 类似的日志记录框架的抽象。因此,您无法比较两者。但是,在两者之间选择其中一个总是很困难的。

如果可以选择,日志记录抽象总是比日志记录框架更可取。如果您使用日志记录抽象,特别是 SLF4J,您可以在部署时迁移到所需的任何日志记录框架,而无需选择单一依赖项。

观察下图以更好地理解。

Application

SLF4J - 环境设置

在本章中,我们将解释如何在 Eclipse IDE 中设置 SLF4J 环境。在继续安装之前,请确保您的系统中已安装 Eclipse。如果没有,请下载并安装 Eclipse。

有关 Eclipse 的更多信息,请参阅我们的 Eclipse 教程

步骤 1:下载依赖项 JAR 文件

打开 SLF4J 网站的官方主页并转到下载页面。

SLF4J 主页

现在,根据您的操作系统(如果是 Windows .zip 文件或 Linux tar.gz)下载最新稳定版本的 slf4j-X.X.tar.gzslf4j-X.X.zip文件)。

在下载的文件夹中,您将找到 slf4j-api-X.X.jar。这是所需的 Jar 文件。

第 2 步:创建项目并设置构建路径

打开 eclipse 并创建一个示例项目。右键单击项目,选择选项 Build Path →按照以下方式配置构建路径…

项目和设置构建路径

Libraries选项卡中的Java Build Path框架中,单击Add External JARs…

Java Build Path

选择下载的slf4j-api.x.x.jar文件,然后单击Apply and Close

Apply And Close

SLF4J Bindings

除了slf4j-api.x.x.jar 文件,SLF4J 提供了其他几个 Jar 文件,如下所示。这些被称为 SLF4J 绑定

SLF4J Bindings

其中每个绑定都适用于其各自的日志记录框架。

下表列出了 SLF4J 绑定及其对应的框架。

Sr.No Jar 文件 &日志记录框架
1

slf4j-nop-x.x.jar

无操作,丢弃所有日志记录。

2

slf4j-simple-x.x.jar

简单实现,其中打印信息及更高级别的消息,其余所有输出到 System.err。

3

slf4j-jcl-x.x.jar

Jakarta Commons 日志记录框架。

4

slf4j-jdk14-x.x.jar

Java.util.logging 框架 (JUL)。

5

slf4j-log4j12-x.x.jar

Log4J 框架。此外,您还需要 log4j.jar

要使 SLF4J 与 slf4l-api-x.x.jar 一起工作,您需要在项目的类路径 (设置构建路径) 中添加所需记录器框架的相应 Jar 文件 (绑定)。

要从一个框架切换到另一个框架,您需要替换相应的绑定。如果未找到边界,则默认为无操作模式。

SLF4J 的 Pom.xml

如果您正在创建 maven 项目,请打开 pom.xml 并将以下内容粘贴到其中并刷新项目。

<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   
   <modelVersion>4.0.0</modelVersion>
   <groupId>Sample</groupId>
   <artifactId>Sample</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <build>
      <sourceDirectory>src</sourceDirectory>
      <plugins>
         <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
               <source>1.8</source>
               <target>1.8</target>
            </configuration>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.25</version>
      </dependency>
   </dependencies>
</project>

SLF4J - 参考 API

在本章中,我们将讨论本教程后续章节中将使用的类和方法。

记录器接口

org.slf4j 包的记录器接口是 SLF4J API 的入口点。下面列出了此接口的重要方法。

Sr.No. 方法和说明
1

void debug(String msg)

此方法在 DEBUG 级别记录一条消息。

2

void error(String msg)

此方法在 ERROR 级别记录一条消息。

3

void info(String msg)

此方法在 INFO 级别记录一条消息。

4

void trace(String msg)

此方法在 TRACE 级别记录一条消息。

5

void warn(String msg)

此方法在 WARN 级别记录一条消息。

LoggerFactory 类

org.slf4j 包的 LoggerFactory 类是一个实用程序类,用于为各种日志记录 API(如 log4j、JUL、NOP 和简单记录器)生成记录器。

Sr.No. 方法和说明
1

Logger getLogger(String name)

此方法接受表示名称的字符串值并返回具有指定名称的 Logger 对象。

Profiler 类

此类属于包 org.slf4j,用于分析目的,被称为穷人的分析器。使用此功能,程序员可以找出执行长时间任务所需的时间。

以下是此类的重要方法。

Sr.No. 方法和说明
1

void start(String name)

此方法将启动一个新的子秒表(命名)并停止之前的子秒表(或时间仪器)。

2

TimeInstrument stop()

此方法将停止最近的子秒表和全局秒表并返回当前的时间仪器。

3

void setLogger(Logger logger)

此方法接受 Logger 对象并将指定的记录器与当前 Profiler 关联。

4

void log()

记录与记录器关联的当前时间仪器的内容。

5

void print()

打印当前时间仪器的内容。

SLF4J - Hello world

在本章中,我们将看到一个使用 SLF4J 的简单基本记录器程序。按照下面描述的步骤编写一个简单的记录器。

步骤 1 - 创建 slf4j.Logger 接口的对象

由于 slf4j.Logger 是 SLF4J API 的入口点,因此首先,您需要获取/创建其对象

LoggerFactory 类的 getLogger() 方法接受表示名称的字符串值并返回具有指定名称的 Logger 对象。

Logger logger = LoggerFactory.getLogger("SampleLogger");

步骤 2 - 记录所需消息

slf4j.Logger 接口的 info() 方法接受表示所需消息的字符串值,并将其记录在信息级别。

logger.info("Hi This is my first SLF4J program");

示例

以下程序演示了如何使用 SLF4J 用 Ja​​va 编写示例记录器。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4JExample {
   public static void main(String[] args) {
        //创建 Logger 对象
        Logger logger = LoggerFactory.getLogger("SampleLogger");
        
        //记录信息
      	logger.info("Hi This is my first SLF4J program");
   }
}

输出

首次运行以下程序时,您将获得以下输出,而不是所需的消息。

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.

由于我们尚未将类路径设置为任何表示日志记录框架的绑定,如本教程前面所述,SLF4J 默认为无操作实现。因此,要查看该消息,您需要在项目类路径中添加所需的绑定。由于我们使用的是 eclipse,请为相应的 JAR 文件设置构建路径,或者在 pom.xml 文件中添加其依赖项。

例如,如果我们需要使用 JUL(Java.util.logging 框架),我们需要为 jar 文件slf4j-jdk14-x.x.jar设置构建路径。如果我们想使用log4J日志框架,我们需要设置构建路径,或者为jar​​文件slf4j-log4j12-x.x.jarlog4j.jar添加依赖项。

将代表除slf4j-nopx.x.jar之外的任何日志框架的绑定添加到项目(类路径)后,您将获得以下输出。

Dec 06, 2018 5:29:44 PM SLF4JExample main
INFO: Hi Welcome to Tutorialspoint

SLF4J - 错误消息

在本章中,我们将讨论使用 SLF4J 时收到的各种错误消息或警告以及这些消息的原因/含义。

无法加载类"org.slf4j.impl.StaticLoggerBinder"。

这是在类路径中未提供 SLF4J 绑定时引发的警告。

以下是完整的警告 −

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.

要解决此问题,您需要添加任一日志记录框架绑定。本教程的 Hello world 一章对此进行了解释。

注意 − 这发生在 1.6.0 和 1.8.0-beta2 之间的 SLF4J 版本中。

未找到 SLF4J 提供程序

在 slf4j-1.8.0-beta2 中,上述警告更明确地表示 "未找到 SLF4J 提供程序"

以下是完整的警告 −

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.

Classpath 包含针对 1.8 之前的 slf4j-api 版本的 SLF4J 绑定

如果您使用的是 SLF4J 1.8 版本,并且类路径中有以前版本的绑定,但没有 1.8 的绑定,您将看到如下所示的警告。

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#noProviders for further details.
SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions prior to
1.8.
SLF4J: Ignoring binding found at
[jar:file:/C:/Users/Tutorialspoint/Desktop/Latest%20Tutorials/SLF4J%20Tutorial/
slf4j-1.7.25/slf4j-jdk14-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#ignoredBindings for an explanation.

NoClassDefFoundError: org/apache/commons/logging/LogFactory

如果您正在使用 slf4j-jcl,并且您的类路径中只有 slf4j-jcl.jar,您将收到如下所示的异常。

Exception in thread "main" java.lang.NoClassDefFoundError:
org/apache/commons/logging/LogFactory
   at org.slf4j.impl.JCLLoggerFactory.getLogger(JCLLoggerFactory.java:77)
   at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358)
   at SLF4JExample.main(SLF4JExample.java:8)
Caused by: java.lang.ClassNotFoundException:
org.apache.commons.logging.LogFactory
   at java.net.URLClassLoader.findClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
   at java.lang.ClassLoader.loadClass(Unknown Source)
   ... 3 more

要解决此问题,您需要将 commons-logging.jar 添加到您的类路径中。

在类路径上检测到 jcl-over-slf4j.jar 和绑定的 slf4j-jcl.jar。

绑定 slf4j-jcl.jar 将 slf4j 记录器的调用重定向到 JCL,而 jcl-over-slf4j.jar 将 JCL 记录器的调用重定向到 slf4j。因此,您不能将这两者同时放在项目的类路径中。如果这样做,您将收到如下所示的异常。

SLF4J: Detected both jcl-over-slf4j.jar AND bound slf4j-jcl.jar on the class
path, preempting StackOverflowError.
SLF4J: See also http://www.slf4j.org/codes.html#jclDelegationLoop for more
details.
Exception in thread "main" java.lang.ExceptionInInitializerError
   at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:71)
   at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:42)
   at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
   at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
   at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)
   at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
   at SLF4JExample.main(SLF4JExample.java:8)
Caused by: java.lang.IllegalStateException: Detected both jcl-over-slf4j.jar
AND bound slf4j-jcl.jar on the class path, preempting StackOverflowError. See
also http://www.slf4j.org/codes.html#jclDelegationLoop for more details.
   at org.slf4j.impl.JCLLoggerFactory.<clinit>(JCLLoggerFactory.java:54)
   ... 7 more

要解决此问题,请删除其中一个 jar 文件。

检测到的记录器名称不匹配

您可以通过以下方式创建 Logger 对象 −

  • 将要创建的记录器的名称作为参数传递给 getLogger() 方法。

  • 将类作为参数传递给此方法。

如果您尝试通过将类作为参数传递来创建记录器工厂对象,并且如果您已将系统属性 slf4j.detectLoggerNameMismatch 设置为 true,则您作为参数传递给 getLogger() 方法的类的名称与您使用的类的名称应该相同,否则您将收到以下警告 −

"检测到记录器名称不匹配。

请考虑以下示例。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4JExample {
   public static void main(String[] args) {
      	System.setProperty("slf4j.detectLoggerNameMismatch", "true");
      
        //创建 Logger 对象
        Logger logger = LoggerFactory.getLogger(Sample.class);
        
        //记录信息
      	logger.info("Hi Welcome to Tutorilspoint");
   }
}

在这里,我们将 slf4j.detectLoggerNameMismatch 属性设置为 true。我们使用的类的名称是 SLF4JExample,我们传递给 getLogger() 方法的类名称是 Sample,因为它们不相等,所以我们会收到以下警告。

SLF4J: Detected logger name mismatch. Given name: "Sample"; computed name:
"SLF4JExample".
SLF4J: See http://www.slf4j.org/codes.html#loggerNameMismatch for an
explanation
Dec 10, 2018 12:43:00 PM SLF4JExample main
INFO: Hi Welcome to Tutorilspoint

注意 − 这发生在 slf4j 1.7.9 之后

类路径包含多个 SLF4J 绑定。

类路径中应该只有一个绑定。如果有多个绑定,您将收到一个警告,其中列出了绑定及其位置。

假设,如果我们在类路径中有绑定 slf4j-jdk14.jarslf4j-nop.jar,我们将收到以下警告。

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in
[jar:file:/C:/Users/Tutorialspoint/Desktop/Latest%20Tutorials/SLF4J%20Tutorial/
slf4j-1.7.25/slf4j-nop-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in
[jar:file:/C:/Users/Tutorialspoint/Desktop/Latest%20Tutorials/SLF4J%20Tutorial/
slf4j-1.7.25/slf4j-jdk14-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an
explanation.
SLF4J: Actual binding is of type [org.slf4j.helpers.NOPLoggerFactory]

在类路径上检测到 log4j-over-slf4j.jar 和绑定的 slf4j-log4j12.jar

要将 log4j 记录器调用重定向到 slf4j,您需要使用 log4j-over-slf4j.jar 绑定,如果您想将 slf4j 调用重定向到 log4j,您需要使用 slf4j-log4j12.jar 绑定。

因此,您不能在类路径中同时拥有两者。如果这样做,您将收到以下异常。

SLF4J: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the
class path, preempting StackOverflowError.
SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more
details.
Exception in thread "main" java.lang.ExceptionInInitializerError
   at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:72)
   at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:45)
   at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
   at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
   at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)
   at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
   at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)
   at SLF4JExample.main(SLF4JExample.java:8)
Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar
AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError.
See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.

SLF4J - 参数化日志记录

如本教程前面所述,SLF4J 提供对参数化日志消息的支持。

您可以在消息中使用参数,并稍后在同一语句中将值传递给它们。

语法

如下所示,您需要在消息(字符串)中需要的任何位置使用占位符 ({}),稍后您可以以 object 形式传递占位符的值,用逗号分隔消息和值。

Integer age;
Logger.info("At the age of {} ramu got his first job", age);

示例

以下示例演示了使用 SLF4J 的参数化日志记录(带有单个参数)。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PlaceHolders {
   public static void main(String[] args) {
      
      //创建 Logger 对象
      Logger logger = LoggerFactory.getLogger(PlaceHolders.class);
      Integer age = 23;
      
      //记录信息
      logger.info("At the age of {} ramu got his first job", age);
   }
}

输出

执行后,上述程序生成以下输出 −

Dec 10, 2018 3:25:45 PM PlaceHolders main
INFO: At the age of 23 Ramu got his first job

参数化日志记录的优势

在 Java 中,如果我们需要在语句中打印值,我们将使用连接运算符 −

System.out.println("At the age of "+23+" ramu got his first job");

这涉及将整数值 23 转换为字符串,并将该值连接到它周围的字符串。

如果它是一个日志记录语句,并且如果语句的特定日志级别被禁用,那么所有这些计算都将毫无用处。

在这种情况下,您可以使用参数化日志记录。在这种格式中,SLF4J 首先确认特定级别的日志记录是否已启用。如果是,则它会将消息中的占位符替换为相应的值。

例如,如果我们有一条语句,如下所示

Integer age;
Logger.debug("At the age of {} ramu got his first job", age);

只有启用了调试,SLF4J 才会将年龄转换为整数并将其与字符串连接起来,否则,它什么也不做。因此,在禁用日志记录级别时会产生参数构造的成本。

双参数变体

您还可以在消息中使用两个参数,如下所示 −

logger.info("Old weight is {}. new weight is {}.", oldWeight, newWeight);

示例

以下示例演示了参数化日志记录中两个占位符的用法。

import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PlaceHolders {
   public static void main(String[] args) {
      Integer oldWeight;
      Integer newWeight;
      Scanner sc = new Scanner(System.in);
      System.out.println("Enter old weight:");
      oldWeight = sc.nextInt();

      System.out.println("Enter new weight:");
      newWeight = sc.nextInt();

      //创建 Logger 对象
      Logger logger = LoggerFactory.getLogger(Sample.class);

      //记录信息
      logger.info("Old weight is {}. new weight is {}.", oldWeight, newWeight);
 
      //记录信息
      logger.info("After the program weight reduced is: "+(oldWeight-newWeight));
   }
}

输出

执行后,上述程序生成以下输出。

Enter old weight:
85
Enter new weight:
74
Dec 10, 2018 4:12:31 PM PlaceHolders main
INFO: Old weight is 85. new weight is 74.
Dec 10, 2018 4:12:31 PM PlaceHolders main
INFO: After the program weight reduced is: 11

多参数变体

您还可以使用两个以上的占位符,如以下示例所示 −

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PlaceHolders {
   public static void main(String[] args) {
      Integer age = 24;
      String designation = "Software Engineer";
      String company = "Infosys";

      //创建 Logger 对象
      Logger logger = LoggerFactory.getLogger(Sample.class);

      //记录信息
      logger.info("At the age of {} ramu got his first job as a {} at {}", age, designation, company);
   }
}

输出

执行后,上述程序生成以下输出 −

Dec 10, 2018 4:23:52 PM PlaceHolders main
INFO: At the age of 24 ramu got his first job as a Software Engineer at Infosys

SLF4J - 迁移器

如果您在 Jakarta Commons Logging (JCL) 或 log4j 或 java.util.logging (JUL) 中有一个项目,并且想要将这些项目转换为 SLF4J,则可以使用 SLF4J 发行版中提供的迁移器工具进行转换。

Migrator

运行 SLF4J 迁移器

SLF4J 是一个简单的单个 jar 文件 (slf4j-migrator.jar),您可以使用 java –jar 命令运行它。

要运行它,请在命令提示符中浏览此 jar 文件的目录并执行以下命令。

java -jar slf4j-migrator-1.8.0-beta2.jar
Starting SLF4J Migrator

这将启动迁移器,您可以看到一个独立的 Java 应用程序作为 −

迁移器项目

如窗口中所指定,您需要检查要执行的迁移类型并选择项目目录,然后单击"将项目迁移到 SLF4J"按钮。

此工具转到您提供的源文件并执行简单的修改,例如将导入行和记录器声明从当前日志记录框架更改为 SLF4j。

示例

例如,假设我们在 eclipse 中有一个示例 log4j(2) 项目,其中包含一个文件,如下所示 −

import org.apache.log4j.Logger;
import java.io.*;
import java.sql.SQLException;
import java.util.*;

public class Sample {
   /* 获取要打印的实际类名 */
   static Logger log = Logger.getLogger(Sample.class.getName());

   public static void main(String[] args)throws IOException,SQLException {
      log.debug("Hello this is a debug message");
      log.info("Hello this is an info message");
   }
}

要将示例 log4j(2) 项目迁移到 slf4j,我们需要选中单选按钮 从 log4j 到 slf4j,并选择项目的目录,然后单击 退出 进行迁移。

项目目录

迁移器将上述代码更改如下。在这里,您可以观察到 import 和 logger 语句已被修改。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.sql.SQLException;
import java.util.*;

public class Sample {
   static Logger log = LoggerFactory.getLogger(Sample.class.getName());
   public static void main(String[] args)throws IOException,SQLException {
      log.debug("Hello this is a debug message");
      log.info("Hello this is an info message");
   }
}

由于您的项目中已经有 log4j.jar,因此您需要将 slf4j-api.jarslf4jlog12.jar 文件添加到项目中才能执行它。

SLF4JMigrator 的限制

以下是 SLF4J 迁移器的限制。

  • 迁移器不会修改 ant、maven 和 ivy 等构建脚本,您需要自己动手。

  • 迁移器不支持除 String 类型之外的消息。

  • 迁移器不支持 FATAL 级别。

  • 在使用 log4j 时,迁移器不会迁移对 PropertyConfigurator 或 DomConfigurator 的调用。

SLF4J - 分析

SLF4J 发行版提供 slf4j-ext.jar,其中包含用于分析、扩展日志记录、事件日志记录和使用 Java 代理进行日志记录等功能的 API。

分析

有时程序员想要测量一些属性,如内存使用、时间复杂度或程序特定指令的使用,以测量该程序的实际能力。这种对程序的测量称为分析。分析使用动态程序分析来进行此类测量。

SLF4J 在 org.slf4j.profiler 包中提供了一个名为 Profiler 的类用于分析目的。这被称为穷人的分析器。使用它,程序员可以找出执行长时间任务所花费的时间。

使用 Profiler 类进行分析

分析器包含秒表和子秒表,我们可以使用分析器类提供的方法启动和停止它们。

要继续使用分析器类进行分析,请按照以下步骤操作。

步骤 1 - 实例化分析器类

通过传递表示分析器名称的字符串值来实例化分析器类。当我们实例化 Profiler 类时,将启动全局秒表。

//创建分析器
Profiler profiler = new Profiler("Sample");

步骤 2 - 启动子秒表

当我们调用 start() 方法时,它将启动一个新的子秒表(已命名)并停止之前的子秒表(或时间仪器)。

通过传递表示要创建的子秒表名称的字符串值来调用 Profiler 类的 start() 方法。

//启动子秒表并停止前一个子秒表。
profiler.start("Task 1");
obj.demoMethod1();

创建这些秒表后,您可以执行任务或调用运行任务的方法。

步骤 3:启动另一个子秒表(如果您愿意)

如果需要,使用 start() 方法创建另一个秒表并执行所需的任务。如果这样做,它将启动一个新的秒表并停止前一个秒表(即任务 1)。

//启动另一个子秒表并停止前一个秒表。
profiler.start("Task 2");
obj.demoMethod2();

步骤 4:停止手表

当我们调用 stop() 方法时,它将停止最近的子秒表和全局秒表并返回当前的时间仪器。

// 停止当前子秒表和全局秒表。
TimeInstrument tm = profiler.stop();

步骤 5:打印时间仪器的内容。

使用 print() 方法打印当前时间仪器的内容。

//打印时间仪器的内容
tm.print();

示例

以下示例演示了使用 SLF4J 的 Profiler 类进行分析。这里我们取了两个示例任务,打印 1 到 10000 之间的数字的平方和,打印 1 到 10000 之间的数字的总和。我们试图获取这两个任务所花费的时间。

import org.slf4j.profiler.Profiler;
import org.slf4j.profiler.TimeInstrument;

public class ProfilerExample {
   public void demoMethod1(){
      double sum = 0;
      for(int i=0; i< 1000; i++){
         sum = sum+(Math.pow(i, 2));
      }
      System.out.println("Sum of squares of the numbers from 1 to 10000: "+sum);
   }
   public void demoMethod2(){
      int sum = 0;
      for(int i=0; i< 10000; i++){
         sum = sum+i;
      }
      System.out.println("Sum of the numbers from 1 to 10000: "+sum);
   }
   public static void main(String[] args) {
    ProfilerExample obj = new ProfilerExample();
    
    //创建一个分析器
    Profiler profiler = new Profiler("Sample");
    
    //启动一个子秒表并停止前一个秒表。
    profiler.start("Task 1");
    obj.demoMethod1();
    
    //启动另一个子秒表并停止前一个秒表。
    profiler.start("Task 2");
    obj.demoMethod2();
    
    //停止当前子秒表和全局秒表。
    TimeInstrument tm = profiler.stop();
    
    //打印时间仪器的内容
    tm.print();
   }
}

输出

执行后,上述程序生成以下输出 −

Sum of squares of the numbers from 1 to 10000: 3.328335E8
Sum of the numbers from 1 to 10000: 49995000
+ Profiler [BASIC]
|-- elapsed time [Task 1] 2291.827 microseconds.
|-- elapsed time [Task 2] 225.802 microseconds.
|-- Total [BASIC] 3221.598 microseconds.

记录分析器信息

您无需打印分析器的结果来记录此信息,而是需要 −

  • 使用 LoggerFactory 类创建记录器。

  • 通过实例化 Profiler 类来创建分析器。

  • 通过将创建的记录器对象传递给 Profiler 类的 setLogger() 方法,将记录器与分析器关联。

  • 最后,使用 log() 方法记录分析器的信息,而不是打印。

示例

在下面的示例中,与上一个示例(而不是打印)不同,我们尝试记录时间仪器的内容。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.profiler.Profiler;
import org.slf4j.profiler.TimeInstrument;

public class ProfilerExample_logger {
   public void demoMethod1(){
      double sum = 0;
      for(int i=0; i< 1000; i++){
         sum = sum+(Math.pow(i, 2));
      }
      System.out.println("Sum of squares of the numbers from 1 to 10000: "+sum);
   }
   public void demoMethod2(){
      int sum = 0;
      for(int i=0; i< 10000; i++){
         sum = sum+i;
      }
      System.out.println("Sum of the numbers from 1 to 10000: "+sum);
   }
   public static void main(String[] args) {
    ProfilerExample_logger obj = new ProfilerExample_logger();
    
    //创建一个记录器
    Logger logger = LoggerFactory.getLogger(ProfilerExample_logger.class);
    
    //创建一个分析器
    Profiler profiler = new Profiler("Sample");
    
    //将记录器添加到分析器
    profiler.setLogger(logger);
    
    //启动子秒表并停止前一个秒表。
    profiler.start("Task 1");
    obj.demoMethod1();
    
    //启动另一个子秒表并停止前一个秒表。
    profiler.start("Task 2");
    obj.demoMethod2();
    
    //停止当前子秒表和全局秒表。
    TimeInstrument tm = profiler.stop();
    
    //记录时间仪器的内容
    tm.log();
   }
}

输出

执行后,上述程序生成以下输出。

Sum of squares of the numbers from 1 to 10000: 3.328335E8
Sum of the numbers from 1 to 10000: 49995000