Slf4j 简明教程

SLF4J - Quick Guide

SLF4J - Overview

SLF4J 代表 S*imple *L*ogging *F*acade for *J*ava. It provides a simple abstraction of all the logging frameworks in Java. Thus, it enables a user to work with any of the logging frameworks such as Log4j, Logback and *JUL (java.util.logging),使用单一依赖。你可以在运行时/部署时迁移到所需的日志记录框架。

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

slf4j api jar

Advantages of SLF4J

以下是 SLF4J 的优点:

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

  2. Slf4J 为所有流行的日志记录框架(例如 log4j、JUL、简单日志记录和 NOP)提供绑定。因此,你可以在部署时切换到其中任何一个流行框架。

  3. 无论你使用哪种绑定,SLF4J 都为参数化日志记录消息提供支持。

  4. 由于 SLF4J 将应用程序与日志记录框架解耦,因此你可以轻松地编写独立于日志记录框架的应用程序。你无需担心正在用于编写应用程序的日志记录框架。

  5. SLF4J 提供一个名为 migrator 的简单 Java 工具。利用此工具,您可以将以前使用 Jakarta Commons Logging (JCL)、log4j 或 Java.util.logging (JUL) 等日志框架的项目迁移到 SLF4J。

SLF4J - Logging Frameworks

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

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

Logging Framework Overview

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

Logger

捕获消息和元数据。

Formatter

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

Handler

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

一些框架将记录器和附录器元素结合在一起,以加快操作速度。

Logger Object

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

Severity Level

记录的消息将具有不同的级别。下表列出了常规的记录级别。

Sr.No

Severity level & Description

1

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

2

ERROR Runtime errors.

3

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

4

INFO 在运行时发生的事件。

5

DEBUG 关于系统流程的信息。

6

TRACE 关于系统流程的更详细信息。

SLF4J Vs Log4j

What is log4j?

Log4j 是一个可靠、快速且灵活的 logging framework (APIs) written in Java ,它在 Apache 软件许可证下分发。

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

Comparison SLF4J and Log4j

与 log4j 不同,SLF4J( S*imple *L*ogging *F*acade for *J*ava) is not an implementation of logging framework, it is an *abstraction for all those logging frameworks in Java similar to log4J 。因此,您无法对比两者。不过,在两者之间做出取舍总是困难的。

如果您有选择,日志记录抽象总是优于日志记录框架。如果您使用日志记录抽象,特别是 SLF4J,则您可以在部署时迁移到任何需要的日志记录框架,而无需选择单一依赖关系。

观察以下图表以更好地理解。

application

SLF4J - Environment Setup

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

欲了解更多有关 Eclipse 的信息,请参阅我们的 Eclipse Tutorial

Step 1: Download the dependency JAR file

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

slf4j homepage

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

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

Step 2: Create a project and set build path

打开 Eclipse 并创建一个示例项目。右键单击该项目,选择选项 Build Path → Configure Build Path… ,如下所示。

project and set 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 bindings

slf4j bindings

其中每个绑定都针对其各自的日志记录框架。

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

Sr.No

Jar 文件和日志记录框架

1

slf4j-nop-x.x.jar 无操作,丢弃所有日志记录。

2

slf4j-simple-x.x.jar 简单实现,其中打印 info 和更高的消息,以及将所有剩余输出输出到 System.err。

3

slf4j-jcl-x.x.jar Jakarta Commons Logging framework.

4

slf4j-jdk14-x.x.jar Java.util.logging framework (JUL).

5

slf4j-log4j12-x.x.jar Log4J 框架。此外,你还需要 log4j.jar

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

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

Pom.xml for SLF4J

如果你正在创建 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 - Referenced API

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

Logger Interface

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

Sr.No.

Methods and Description

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 Class

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

Sr.No.

Method and Description

1

Logger getLogger(String name) 此方法接受表示名称的字符串值,并使用指定名称返回 Logger 对象。

Profiler Class

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

以下是此类的重要方法。

Sr.No.

Methods and Description

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 的简单基本记录程序。按照以下描述的步骤编写一个简单的记录程序。

Step 1 - Create an object of the slf4j.Logger interface

因为 slf4j.Logger 是 SLF4J API 的入口点,您首先需要获取/创建它的对象。

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

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

Step 2 - Log the required message

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

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

Example

以下是演示如何使用 SLF4J 在 Java 中编写示例记录程序的程序。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4JExample {
   public static void main(String[] args) {
      //Creating the Logger object
      Logger logger = LoggerFactory.getLogger("SampleLogger");

      //Logging the information
      logger.info("Hi This is my first SLF4J program");
   }
}

Output

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

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 文件设置 build path ,或在 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 - Error Messages

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

Failed to load class "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 章中进行说明的。

Note − 这种情况发生在 SLF4J 1.6.0 至 1.8.0-beta2 之间的版本中。

No SLF4J providers were found

在 slf4j-1.8.0-beta2 中,上述警告更清楚地说 “No SLF4J providers were found”

以下是完整的警告 −

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 contains SLF4J bindings targeting slf4j-api versions prior to 1.8

如果您使用的是 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 添加到你的 classpath 中。

Detected both jcl-over-slf4j.jar AND bound slf4j-jcl.jar on the classpath..

绑定 slf4j-jcl.jar 将 SLF4J 日志记录器的调用重定向到 JCL,绑定 jcl-over-slf4j.jar 将 JCL 日志记录器的调用重定向到 SLF4J。因此,在项目的 classpath 中无法同时拥有这两者。如果你这样做,将会收到类似于以下内容的异常。

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 文件中的任意一个。

Detected logger name mismatch

你可以通过下列方式创建日志记录器对象:

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

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

如果你试图通过将类作为参数传递来创建日志记录器工厂对象,而且你将系统属性 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");

      //Creating the Logger object
      Logger logger = LoggerFactory.getLogger(Sample.class);

      //Logging the information
      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

Note - 这发生在 SLF4J 1.7.9 之后

Classpath contains multiple SLF4J bindings.

你应该在 classpath 中只保留一个绑定。如果你有多个绑定,你将会收到一条警告,列出这些绑定及其位置。

假设 classpath 中有绑定 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]

Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path

要将 Log4j 日志记录器调用重新定向到 SLF4J,你需要使用 log4j-over-slf4j.jar 绑定,如果你想将 SLF4J 调用重新定向到 Log4j,则需要使用 slf4j-log4j12.jar 绑定。

因此,你不能在 classpath 中同时拥有两者。如果你这样做,你会收到以下异常。

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 - Parameterized logging

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

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

Syntax

如下所示,您需要在消息(字符串)中使用占位符({}),只要您需要在 object 形式中传递值,并使用逗号分隔消息和值。

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

Example

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PlaceHolders {
   public static void main(String[] args) {

      //Creating the Logger object
      Logger logger = LoggerFactory.getLogger(PlaceHolders.class);
      Integer age = 23;

      //Logging the information
      logger.info("At the age of {} ramu got his first job", age);
   }
}

Output

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

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

Advantage of Parameterized Logging

在 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 才会将年龄转换成整数,并在字符串连接它,否则它将不执行任何操作。因此,如果禁用日志记录级别,将导致参数构造成本。

Two Argument Variant

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

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

Example

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

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();

      //Creating the Logger object
      Logger logger = LoggerFactory.getLogger(Sample.class);

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

      //Logging the information
      logger.info("After the program weight reduced is: "+(oldWeight-newWeight));
   }
}

Output

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

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

Multiple Argument Variant

您还可以使用多个占位符,如下面的示例所示:

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";

      //Creating the Logger object
      Logger logger = LoggerFactory.getLogger(Sample.class);

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

Output

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

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 - Migrator

如果您在 Jakarta Commons Logging (JCL) 或 log4j 或 java.util.logging (JUL) 中有一个项目,并且您希望将这些项目转换为 SLF4J,则可以使用 SLF4J 分发中提供的 migrator 工具来执行此操作。

migrator

Running SLF4J Migrator

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

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

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

这将启动迁移程序,可看到独立的 Java 应用程序,如下所示:

migrator project

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

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

Example

例如,让我们假设我们有一个带一个文件的 log4j(2) 示例项目,如下所示:

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

public class Sample {
   /* Get actual class name to be printed on */
   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,我们需要选中单选按钮 from log4j to slf4j ,并选择项目目录,然后点击 Exit 进行迁移。

directory of the project

迁移程序将按如下方式更改上述代码。此处,如果您观察,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 文件添加到项目中来执行它。

Limitations of SLF4JMigrator

以下是 SLF4J 迁移程序的局限性。

  1. 迁移程序将不会修改构建脚本,如 ant、maven 和 ivy,您需要自己执行此操作。

  2. 迁移程序不支持 String 类型以外的消息。

  3. 迁移程序不支持 FATAL 等级。

  4. 当使用 log4j 时,迁移程序不会迁移到 PropertyConfigurator 或 DomConfigurator 的调用。

SLF4J - Profiling

SLF4J 分发提供 slf4j-ext.jar 这里包含用于分析性能、扩展记录、事件记录和使用 Java 代理记录等功能的 API。

Profiling

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

SLF4J 提供名为 Profiler 的类,位于 org.slf4j.profiler 包中,用于性能分析。这被称为穷人的分析程序。使用此类,程序员可以找出执行较长时间任务所花费的时间。

Profiling Using the Profiler class

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

若要通过 Profiler 类继续进行分析,请按照以下步骤操作。

Step 1 - Instantiate the profiler class

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

//Creating a profiler
Profiler profiler = new Profiler("Sample");

Step 2 - Start a child stopwatch

调用 start() 方法时,将启动一个新的子秒表(命名),并停止较早的子秒表(或时间工具)。

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

//Starting a child stopwatch and stopping the previous one.
profiler.start("Task 1");
obj.demoMethod1();

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

Step 3: Start another child stopwatch (if you wish to)

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

//Starting another child stopwatch and stopping the previous one.
profiler.start("Task 2");
obj.demoMethod2();

Step 4: Stop the watches

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

// Stopping the current child stopwatch and the global stopwatch.
TimeInstrument tm = profiler.stop();

Step 5: Print the contents of the time instrument.

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

//printing the contents of the time instrument
tm.print();

Example

以下示例演示了使用 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();

      //Creating a profiler
      Profiler profiler = new Profiler("Sample");

      //Starting a child stop watch and stopping the previous one.
      profiler.start("Task 1");
      obj.demoMethod1();

      //Starting another child stop watch and stopping the previous one.
      profiler.start("Task 2");
      obj.demoMethod2();

      //Stopping the current child watch and the global watch.
      TimeInstrument tm = profiler.stop();

      //printing the contents of the time instrument
      tm.print();
   }
}

Output

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

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.

Logging the Profiler Information

与其将分析器结果打印到日志中以记录此信息,您需要 -

  1. 使用 LoggerFactory 类创建一个记录器。

  2. 通过实例化 Profiler 类创建分析器。

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

  4. 最后,使用 log() 方法记录分析器信息而不是打印日志。

Example

在以下示例中,与前一个示例不同(而非打印),我们尝试记录时间工具的内容。

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();

      //Creating a logger
      Logger logger = LoggerFactory.getLogger(ProfilerExample_logger.class);

      //Creating a profiler
      Profiler profiler = new Profiler("Sample");

      //Adding logger to the profiler
      profiler.setLogger(logger);

      //Starting a child stop watch and stopping the previous one.
      profiler.start("Task 1");
      obj.demoMethod1();

      //Starting another child stop watch and stopping the previous one.
      profiler.start("Task 2");
      obj.demoMethod2();

      //Stopping the current child watch and the global watch.
      TimeInstrument tm = profiler.stop();

      //Logging the contents of the time instrument
      tm.log();
   }
}

Output

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

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