SLF4J 快速指南
SLF4J - 概述
SLF4J 代表 **S**imple **L**ogging **F**acade for **J**ava。它为 Java 中的所有日志框架提供了一个简单的抽象层。因此,它使用户能够使用单个依赖项与任何日志框架(例如 Log4j、Logback 和 **JUL**(java.util.logging))一起工作。您可以在运行时/部署时迁移到所需的日志框架。
Ceki Gülcü 创建 SLF4J 作为 Jakarta commons-logging 框架的替代方案。
SLF4J 的优势
以下是 SLF4J 的优势:
使用 SLF4J 框架,您可以在部署时迁移到所需的日志框架。
Slf4j 提供了对所有流行的日志框架的绑定,例如 log4j、JUL、Simple logging 和 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 等。
日志框架概述
日志框架通常包含三个元素:
记录器 (Logger)
捕获消息以及元数据。
格式化器 (Formatter)
格式化记录器捕获的消息。
处理器 (Handler)
处理器或追加器最终通过打印到控制台、存储到数据库或通过电子邮件发送来调度消息。
一些框架将记录器和追加器元素组合起来以加快操作速度。
Logger 对象
要记录消息,应用程序会发送一个带有名称和安全级别的 Logger 对象(有时还会包含任何异常)。
严重级别
记录的消息将具有不同的级别。下表列出了日志的一般级别。
序号 | 严重级别及说明 |
---|---|
1 |
致命 (Fatal) 导致应用程序终止的严重问题。 |
2 |
错误 (ERROR) 运行时错误。 |
3 |
警告 (WARNING) 在大多数情况下,错误是由于使用了已弃用的 API。 |
4 |
信息 (INFO) 运行时发生的事件。 |
5 |
调试 (DEBUG) 关于系统流程的信息。 |
6 |
跟踪 (TRACE) 关于系统流程的更详细的信息。 |
SLF4J vs Log4j
什么是 log4j?
log4j 是一个可靠、快速且灵活的 **用 Java 编写的日志框架 (API)**,它在 Apache 软件许可证下发行。
log4j 通过运行时的外部配置文件高度可配置。它从优先级级别来看待日志记录过程,并提供机制将日志信息定向到各种目的地,例如数据库、文件、控制台、UNIX Syslog 等。(有关 log4j 的更多详细信息,请参阅我们的 教程)。
SLF4J 和 Log4j 的比较
与 log4j 不同,SLF4J (**S**imple **L**ogging **F**acade for **J**ava) 不是日志框架的实现,它是 Java 中所有类似于 log4J 的日志框架的 **抽象**。因此,您无法比较两者。但是,总是很难在两者之间进行选择。
如果您有选择,日志抽象总是优于日志框架。如果您使用日志抽象,特别是 SLF4J,您可以在部署时迁移到任何所需的日志框架,而无需选择单个依赖项。
观察下图以更好地理解。
SLF4J - 环境设置
在本章中,我们将解释如何在 Eclipse IDE 中设置 SLF4J 环境。在继续安装之前,请确保您已经在系统中安装了 Eclipse。如果没有,请下载并安装 Eclipse。
有关 Eclipse 的更多信息,请参阅我们的 Eclipse 教程
步骤 1:下载依赖项 JAR 文件
打开 SLF4J 网站的官方 主页 并转到下载页面。
现在,根据您的操作系统下载最新稳定版本的 slf4j-X.X.tar.gz 或 slf4j-X.X.zip(如果使用 Windows,则为 .zip 文件;如果使用 Linux,则为 tar.gz 文件)。
在下载的文件夹中,您将找到 slf4j-api-X.X.jar。这是所需的 Jar 文件。
步骤 2:创建一个项目并设置构建路径
打开 Eclipse 并创建一个示例项目。右键单击项目,选择选项 **构建路径 → 配置构建路径…**,如下所示。
在 **Java 构建路径** 框架的 **库** 选项卡中,单击 **添加外部 JARs…**
选择下载的 slf4j-api.x.x.jar 文件,然后单击 **应用并关闭**。
SLF4J 绑定
除了 slf4j-api.x.x.jar 文件之外,SLF4J 还提供其他几个 Jar 文件,如下所示。这些称为 **SLF4J 绑定**。
每个绑定都对应其各自的日志框架。
下表列出了 SLF4J 绑定及其对应的框架。
序号 | Jar 文件 & 日志框架 |
---|---|
1 |
slf4j-nop-x.x.jar 不执行任何操作,丢弃所有日志。 |
2 |
slf4j-simple-x.x.jar 简单的实现,其中打印信息及以上级别的消息,其余所有输出到 System.err。 |
3 |
slf4j-jcl-x.x.jar Jakarta Commons Logging 框架。 |
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
在本章中,我们将讨论在本教程后续章节中将使用的类和方法。
Logger 接口
org.slf4j 包的 Logger 接口是 SLF4J API 的入口点。以下是此接口的重要方法列表。
序号 | 方法和说明 |
---|---|
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 和 simple logger)生成记录器。
序号 | 方法和说明 |
---|---|
1 | Logger getLogger(String name) 此方法接受表示名称的字符串值,并返回具有指定名称的 **Logger** 对象。 |
Profiler 类
此类属于包 **org.slf4j**,用于性能分析目的,被称为“穷人的性能分析器”。使用它,程序员可以找出执行长时间任务所需的时间。
以下是此类的重要方法。
序号 | 方法和说明 |
---|---|
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()** 方法接受表示所需消息的字符串值,并将其以 info 级别记录。
logger.info("Hi This is my first SLF4J program");
示例
以下程序演示了如何使用 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"); } }
输出
运行以下程序时,您将获得以下输出,而不是所需的消息。
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.jar 和 log4j.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.
要解决这个问题,您需要添加任一日志框架绑定。本教程的HelloWorld章节对此进行了说明。
注意 − 这发生在 SLF4J 1.6.0 到 1.8.0-beta2 版本之间。
未找到任何 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.
类路径包含针对早于 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"); //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
注意 − 这发生在 slf4j 1.7.9 之后
类路径包含多个 SLF4J 绑定。
您应该只在类路径中包含一个绑定。如果您有多个绑定,则会收到一个警告,列出这些绑定及其位置。
例如,如果我们的类路径中包含slf4j-jdk14.jar和slf4j-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 提供了对参数化日志消息的支持。
您可以在消息中使用参数,并在稍后的同一语句中传递值。
语法
如下所示,您需要在消息(字符串)中使用占位符({}),稍后您可以以对象形式为占位符传递值,用逗号分隔消息和值。
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) { //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); } }
输出
执行后,上述程序将生成以下输出:
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(); //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)); } }
输出
执行后,上述程序将生成以下输出。
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"; //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); } }
输出
执行后,上述程序将生成以下输出:
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 分发版中提供的迁移工具。
运行 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 { /* 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,我们需要选中从 log4j 到 slf4j单选按钮,选择项目的目录,然后单击退出以进行迁移。
迁移器将上述代码更改如下。在这里,如果您观察导入和日志器语句,它们已被修改。
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.jar和slf4j-log4j12.jar文件添加到项目中才能执行它。
SLF4JMigrator 的限制
以下是 SLF4J 迁移器的限制。
迁移器不会修改像 ant、maven 和 ivy 这样的构建脚本,您需要自己动手。
迁移器不支持除字符串类型以外的消息。
迁移器不支持 FATAL 级别。
在使用 log4j 时,迁移器不会迁移对 PropertyConfigurator 或 DomConfigurator 的调用。
SLF4J - 性能分析
SLF4J 分发版提供slf4j-ext.jar,其中包含用于分析、扩展日志记录、事件日志记录和使用 Java 代理进行日志记录等功能的 API。
分析
有时程序员想要测量程序的某些属性,例如内存使用情况、时间复杂度或特定指令的使用情况,以衡量该程序的实际能力。这种对程序的测量称为分析。分析使用动态程序分析来进行这种测量。
SLF4J 在org.slf4j.profiler包中提供了一个名为Profiler的类用于分析目的。这被称为“穷人版”分析器。使用它,程序员可以找出执行长时间任务所花费的时间。
使用 Profiler 类进行分析
分析器包含秒表和子秒表,我们可以使用分析器类提供的方法启动和停止它们。
要使用分析器类继续进行分析,请按照以下步骤操作。
步骤 1 - 实例化分析器类
通过传递一个表示分析器名称的字符串值来实例化 Profiler 类。当我们实例化 Profiler 类时,将启动一个全局秒表。
//Creating a profiler Profiler profiler = new Profiler("Sample");
步骤 2 - 启动子秒表
当我们调用start()方法时,它将启动一个新的子秒表(命名),并停止之前的子秒表(或时间工具)。
通过传递一个表示要创建的子秒表名称的字符串值来调用Profiler类的start()方法。
//Starting a child stopwatch and stopping the previous one. profiler.start("Task 1"); obj.demoMethod1();
创建这些秒表后,您可以执行您的任务或调用运行您的任务的那些方法。
步骤 3:启动另一个子秒表(如果您希望)
如果需要,可以使用start()方法创建另一个秒表并执行所需的任务。如果您这样做,它将启动一个新的秒表并停止之前的秒表(即任务 1)。
//Starting another child stopwatch and stopping the previous one. profiler.start("Task 2"); obj.demoMethod2();
步骤 4:停止秒表
当我们调用stop()方法时,它将停止最近的子秒表和全局秒表,并返回当前时间工具。
// Stopping the current child stopwatch and the global stopwatch. TimeInstrument tm = profiler.stop();
步骤 5:打印时间工具的内容。
使用print()方法打印当前时间工具的内容。
//printing the contents of the time instrument 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(); //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(); } }
输出
执行后,上述程序将生成以下输出:
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(); //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(); } }
输出
执行后,上述程序将生成以下输出。
Sum of squares of the numbers from 1 to 10000: 3.328335E8 Sum of the numbers from 1 to 10000: 49995000