Slf4j 简明教程
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),使用单一依赖。你可以在运行时/部署时迁移到所需的日志记录框架。
SLF4J stands for 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) using single dependency. You can migrate to the required logging framework at run-time/deployment time.
Ceki Gülcü 创建了 SLF4J 作为 Jakarta commons-logging 框架的替代品。
Ceki Gülcü created SLF4J as an alternative to Jakarta commons-logging framework.
Advantages of SLF4J
以下是 SLF4J 的优点:
Following are the advantages of SLF4J −
-
Using SLF4J framework, you can migrate to the desired logging framework at the time of deployment.
-
Slf4J provides bindings to all popular logging frameworks such as log4j, JUL, Simple logging and, NOP. Therefore, you can switch to any of these popular frameworks at the time of deployment.
-
SLF4J provides support to parameterized logging messages irrespective of the binding you use.
-
Since SLF4J decouples application and logging framework, you can easily write applications independent of logging frameworks. You need not bother about the logging framework being used to write an application.
-
SLF4J provides a simple Java tool known as migrator. Using this tool, you can migrate existing projects, which use logging frame works like Jakarta Commons Logging (JCL) or, log4j or, Java.util.logging (JUL) to SLF4J.
SLF4J - Logging Frameworks
记录在编程中指的是记录活动/事件。通常,应用程序开发人员应该负责记录。
Logging in programming, refers to recording activities/events. Usually, the application developers should take care of logging.
为了让记录工作变得更容易,Java 提供了各种框架 − log4J、java.util.logging (JUL)、tiny log、logback 等。
To make the job of logging easier, Java provides various frameworks − log4J, java.util.logging (JUL), tiny log, logback, etc.
Logging Framework Overview
一个记录框架通常包含三个元素 −
A logging framework usually contains three elements −
Handler
处理程序或附录器最终通过在控制台上打印、存储在数据库中或通过电子邮件发送来调度消息。
The Handler or appender finally dispatches the messages either by printing on the console or, by storing in the database or, by sending through an email.
一些框架将记录器和附录器元素结合在一起,以加快操作速度。
Some frameworks combine the logger and appender elements to speed up the operations.
Logger Object
为了记录消息,应用程序发送一个记录器对象(有时还包括异常,如果存在的话),其中包含名称和安全级别。
To log a message, the application sends a logger object (sometimes along with the exceptions if any) with name and security level.
Severity Level
记录的消息将具有不同的级别。下表列出了常规的记录级别。
The messages logged will be of various levels. The following table lists down the general levels of logging.
Sr.No |
Severity level & Description |
1 |
Fatal Severe issue that causes the application to terminate. |
2 |
ERROR Runtime errors. |
3 |
WARNING In most cases, the errors are due to the usage of deprecated APIs. |
4 |
INFO Events that occur at runtime. |
5 |
DEBUG Information about the flow of the system. |
6 |
TRACE More detailed information about the flow of the system. |
SLF4J Vs Log4j
What is log4j?
Log4j 是一个可靠、快速且灵活的 logging framework (APIs) written in Java ,它在 Apache 软件许可证下分发。
log4j is a reliable, fast and flexible logging framework (APIs) written in Java, which is distributed under the Apache Software License.
Log4j 可以通过外部配置文件在运行时进行高度配置。它将日志记录过程视为具有优先级,并提供将日志记录信息定向到各种目的地的机制,例如数据库、文件、控制台、UNIX Syslog 等(有关 Log4j 的更多详细信息,请参阅我们的 Tutorial )。
log4j is highly configurable through external configuration files at runtime. It views the logging process in terms of levels of priorities and offers mechanisms to direct logging information to a great variety of destinations, such as a database, file, console, UNIX Syslog, etc. (for more details on log4j refer our 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 。因此,您无法对比两者。不过,在两者之间做出取舍总是困难的。
Unlike 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. Therefore, you cannot compare both. However, it is always difficult to prefer one between the two.
如果您有选择,日志记录抽象总是优于日志记录框架。如果您使用日志记录抽象,特别是 SLF4J,则您可以在部署时迁移到任何需要的日志记录框架,而无需选择单一依赖关系。
If you have a choice, logging abstraction is always preferable than logging framework. If you use a logging abstraction, SLF4J in particular, you can migrate to any logging framework you need at the time of deployment without opting for single dependency.
观察以下图表以更好地理解。
Observe the following diagram to have a better understanding.
SLF4J - Environment Setup
在本章中,我们将讲解如何在 Eclipse IDE 中设置 SLF4J 环境。在继续安装之前,请确保您的系统中已安装 Eclipse。如果没有,请下载并安装 Eclipse。
In this chapter, we will explain how to set SLF4J environment in Eclipse IDE. Before proceeding with the installation, make sure that you already have Eclipse installed in your system. If not, download and install Eclipse.
欲了解更多有关 Eclipse 的信息,请参阅我们的 Eclipse Tutorial
For more information on Eclipse, please refer our Eclipse Tutorial
Step 1: Download the dependency JAR file
打开 SLF4J 网站的官方 homepage ,并转到下载页面。
Open the official homepage of the SLF4J website and go to the download page.
现在,根据您的操作系统下载 slf4j-X.X.tar.gz 或 slf4j-X.X.zip 的最新稳定版本(如果为 Windows,则为 .zip 文件,如果为 Linux,则为 tar.gz 文件)。
Now, download the latest stable version of slf4j-X.X.tar.gz or slf4j-X.X.zip, according to your operating system (if windows .zip file or if Linux tar.gz file).
在下载的文件夹中,您将找到 slf4j-api-X.X.jar。这是必需的 Jar 文件。
Within the downloaded folder, you will find slf4j-api-X.X.jar. This is the required Jar file.
Step 2: Create a project and set build path
打开 Eclipse 并创建一个示例项目。右键单击该项目,选择选项 Build Path → Configure Build Path… ,如下所示。
Open eclipse and create a sample project. Right-click on the project, select the option Build Path → Configure Build Path… as shown below.
在 Libraries 标签中的 Java Build Path 框架中,点击 Add External JARs… 。
In the Java Build Path frame in the Libraries tab, click Add External JARs…
选择下载的 slf4j-api.x.x.jar 文件,并点击 Apply and Close 。
Select the slf4j-api.x.x.jar file downloaded and click Apply and Close.
SLF4J Bindings
除了 slf4j-api.x.x.jar 文件之外, SLF4J 还提供了一些其他 Jar 文件,如下所示。它们被称为 SLF4J bindings 。
In addition to slf4j-api.x.x.jar file, SLF4J provides several other Jar files as shown below. These are called SLF4J bindings.
其中每个绑定都针对其各自的日志记录框架。
Where each binding is for its respective logging framework.
下表列出了 SLF4J 绑定及其对应的框架。
The following table lists the SLF4J bindings and their corresponding frameworks.
Sr.No |
Jar file & Logging Framework |
1 |
slf4j-nop-x.x.jar No operation, discards all loggings. |
2 |
slf4j-simple-x.x.jar Simple implementation where messages for info and higher are printed and, remaining all outputs to 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 frame work. In addition, you need to have log4j.jar. |
要让 SLF4J 与 slf4l-api-x.x.jar 一起工作,你需要在该项目(设置构建路径)的类路径中添加所需的记录器框架的相应 Jar 文件(绑定)。
To make SLF4J work along with slf4l-api-x.x.jar, you need to add the respective Jar file (binding) of the desired logger framework in the classpath of the project (set build path).
要从一个框架切换到另一个框架,你需要替换相应的绑定。如果未找到绑定,则它会默认为无操作模式。
To switch from one framework to other, you need to replace the respective binding. If no bounding is found, it defaults to no-operation mode.
Pom.xml for SLF4J
如果你正在创建 maven 项目,请打开 pom.xml 并在其中粘贴以下内容,然后刷新项目。
If you are creating the maven project, open the pom.xml and paste the following content in it and refresh the project.
<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
在本教程的后续章节中,我们将讨论将在其中使用的类和方法。
In this chapter, we will discuss the classes and methods that we will be using in the subsequent chapters of this tutorial.
Logger Interface
org.slf4j 包的记录器接口是 SLF4J API 的入口点。以下是此接口的重要方法列表。
The logger interface of the org.slf4j package is the entry point of the SLF4J API. The following lists down the important methods of this interface.
Sr.No. |
Methods and Description |
1 |
void debug(String msg) This method logs a message at the DEBUG level. |
2 |
void error(String msg) This method logs a message at the ERROR level. |
3 |
void info(String msg) This method logs a message at the INFO level. |
4 |
void trace(String msg) This method logs a message at the TRACE level. |
5 |
void warn(String msg) This method logs a message at the WARN level. |
LoggerFactory Class
org.slf4j 包的 LoggerFactory 类是一个实用程序类,用于为各种日志记录 API 生成记录器,如 log4j、JUL、NOP 和 simple logger。
The LoggerFactory class of the org.slf4j package is a utility class, which is used to generate loggers for various logging APIs such as log4j, JUL, NOP and simple logger.
Sr.No. |
Method and Description |
1 |
Logger getLogger(String name) This method accepts a string value representing a name and returns a Logger object with the specified name. |
Profiler Class
此类属于包 org.slf4j ,用于分析目的,被称为穷人的分析器。使用此类,程序员可以找出执行长时间任务所需的时间。
This class belongs to the package org.slf4j this is used for profiling purpose and it is known as poor man’s profiler. Using this, the programmer can find out the time taken to carry out prolonged tasks.
以下是此类的重要方法。
Following are the important methods of this class.
Sr.No. |
Methods and Description |
1 |
void start(String name) This method will start a new child stop watch (named) and, stops the earlier child stopwatches (or, time instruments). |
2 |
TimeInstrument stop() This method will stop the recent child stopwatch and the global stopwatch and return the current Time Instrument. |
3 |
void setLogger(Logger logger) This method accepts a Logger object and associates the specified logger to the current Profiler. |
4 |
void log() Logs the contents of the current time instrument that is associated with a logger. |
5 |
void print() Prints the contents of the current time instrument. |
SLF4J - Hello world
在本章中,我们将看到一个使用 SLF4J 的简单基本记录程序。按照以下描述的步骤编写一个简单的记录程序。
In this chapter, we will see a simple basic logger program using SLF4J. Follow the steps described below to write a simple logger.
Step 1 - Create an object of the slf4j.Logger interface
因为 slf4j.Logger 是 SLF4J API 的入口点,您首先需要获取/创建它的对象。
Since the slf4j.Logger is the entry point of the SLF4J API, first, you need to get/create its object
LoggerFactory 类的 getLogger() 方法接受一个表示名称的字符串值,并返回一个带有指定名称的 Logger 对象。
The getLogger() method of the LoggerFactory class accepts a string value representing a name and returns a Logger object with the specified name.
Logger logger = LoggerFactory.getLogger("SampleLogger");
Step 2 - Log the required message
slf4j.Logger 接口的 info() 方法接受一个表示所需消息的字符串值,并以信息级别记录它。
The info() method of the slf4j.Logger interface accepts a string value representing the required message and logs it at the info level.
logger.info("Hi This is my first SLF4J program");
Example
以下是演示如何使用 SLF4J 在 Java 中编写示例记录程序的程序。
Following is the program that demonstrates how to write a sample logger in Java using SLF4J.
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
在最初运行以下程序时,您将获得以下输出,而不是所需的消息。
On running the following program initially, you will get the following output instead of the desired message.
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 文件中添加其依赖项。
Since we have not set the classpath to any binding representing a logging framework, as mentioned earlier in this tutorial, SLF4J defaulted to a no-operation implementation. So, to see the message you need to add the desired binding in the project classpath. Since we are using eclipse, set build path for respective JAR file or, add its dependency in the pom.xml file.
例如,如果我们需要使用 JUL(Java.util.logging 框架),则需要为 JAR 文件 slf4j-jdk14-x.x.jar 设置构建路径。如果我们要使用 log4J 日志框架,则需要为 JAR 文件 slf4j-log4j12-x.x.jar 和 log4j.jar 设置构建路径,或添加依赖项。
For example, if we need to use JUL (Java.util.logging framework), we need to set build path for the jar file slf4j-jdk14-x.x.jar. And if we want to use log4J logging framework, we need to set build path or, add dependencies for the jar files slf4j-log4j12-x.x.jar and log4j.jar.
将表示任何日志框架(除 slf4j-nopx.x.jar 以外)的绑定添加到项目(类路径)之后,您将获得以下输出。
After adding the binding representing any of the logging frameworks except slf4j-nopx.x.jar to the project (classpath), you will get the following output.
Dec 06, 2018 5:29:44 PM SLF4JExample main
INFO: Hi Welcome to Tutorialspoint
SLF4J - Error Messages
在本章中,我们将讨论在使用 SLF4J 时收到的各种错误消息或警告,以及这些消息的原因/含义。
In this chapter, we will discuss the various error messages or warning we get while working with SLF4J and the causes/ meanings of those messages.
Failed to load class "org.slf4j.impl.StaticLoggerBinder".
当类路径中没有提供 SLF4J 绑定时,会引发此警告。
This is a warning which is caused when there are no SLF4J bindings provided in the classpath.
以下是完整的警告 −
Following is the complete warning −
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 章中进行说明的。
To resolve this, you need to add either of the logging framework bindings. This is explained in the Hello world chapter of this tutorial.
Note − 这种情况发生在 SLF4J 1.6.0 至 1.8.0-beta2 之间的版本中。
Note − This occurs in versions of SLF4J which are between 1.6.0 and 1.8.0-beta2.
No SLF4J providers were found
在 slf4j-1.8.0-beta2 中,上述警告更清楚地说 “No SLF4J providers were found” 。
In slf4j-1.8.0-beta2, the above warning is more clear saying “No SLF4J providers were found”.
以下是完整的警告 −
Following is the complete warning −
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 的绑定,您将看到如下所示的警告。
If you are using SLF4J 1.8 version and you have the bindings of previous versions in the classpath but not the bindings of 1.8 you will see a warning as shown below.
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 ,您将收到如下所示的异常。
If you are working with slf4j-jcl and if you have only slf4j-jcl.jar in your classpath, you will get an exception such as the one given below.
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 中。
To resolve this, you need to add commons-logging.jar to your 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 中无法同时拥有这两者。如果你这样做,将会收到类似于以下内容的异常。
The binding slf4j-jcl.jar redirects calls of the slf4j logger to JCL and the jcl-over-slf4j.jar redirects calls of JCL logger to slf4j. Therefore, you cannot have both in the classpath of your project. If you do so, you will get an exception such as the one given below.
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 文件中的任意一个。
To resolve this, delete either of the jar files.
Detected logger name mismatch
你可以通过下列方式创建日志记录器对象:
You can create a Logger object by −
-
Passing the name of the logger to be created as an argument to the getLogger() method.
-
Passing a class as an argument to this method.
如果你试图通过将类作为参数传递来创建日志记录器工厂对象,而且你将系统属性 slf4j.detectLoggerNameMismatch 设置为 true,那么你传递给 getLogger() 方法的参数所属类的名称和你使用的类应当相同,否则你会收到下列警告:
If you are trying to create the logger factory object by passing a class as an argument, and if you have set the system property slf4j.detectLoggerNameMismatch to true, then the name of the class you pass as an argument to the getLogger() method and the class you use should be the same otherwise you will receive the following warning −
“检测到日志记录器名称不匹配。
“Detected logger name mismatch.
考虑以下示例。
Consider the following example.
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 ,由于这两个名称不相等,因此会收到以下警告。
Here, we have set the slf4j.detectLoggerNameMismatch property to true. The name of the class we used is SLF4JExample and the class name we have passed to the getLogger() method is Sample since they both are not equal we will get the following warning.
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 之后
Note − This occurs after slf4j 1.7.9
Classpath contains multiple SLF4J bindings.
你应该在 classpath 中只保留一个绑定。如果你有多个绑定,你将会收到一条警告,列出这些绑定及其位置。
You should have only one binding in the classpath. If you have more than one binding, you will get a warning listing the bindings and the locations of them.
假设 classpath 中有绑定 slf4j-jdk14.jar 和 slf4j-nop.jar ,那么我们将会收到以下警告。
For suppose, if we have the bindings slf4j-jdk14.jar and slf4j-nop.jar in the classpath we will get the following warning.
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 绑定。
To redirect the log4j logger calls to slf4j, you need to use log4j-over-slf4j.jar binding and if you want to redirect slf4j calls to log4j, you need to use slf4j-log4j12.jar binding.
因此,你不能在 classpath 中同时拥有两者。如果你这样做,你会收到以下异常。
Therefore, you cannot have both in the classpath. If you do, you will get the following exception.
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 提供对参数化日志消息的支持。
As discussed earlier in this tutorial SLF4J provides support for parameterized log messages.
您可以在消息中使用参数,并在同一语句的后面为它们传递值。
You can use parameters in the messages and pass values to them later in the same statement.
Syntax
如下所示,您需要在消息(字符串)中使用占位符({}),只要您需要在 object 形式中传递值,并使用逗号分隔消息和值。
As shown below, you need to use placeholders ({}) in the message (String) wherever you need and later you can pass value for place holder in object form, separating the message and value with comma.
Integer age;
Logger.info("At the age of {} ramu got his first job", age);
Example
以下示例演示使用 SLF4J 的参数化日志记录(带单个参数)。
The following example demonstrates parameterized logging (with single parameter) using 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
执行后,上述程序生成以下输出 -
Upon execution, the above program generates the following 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 中,如果我们需要在语句中打印值,我们将使用连接运算符,如下所示:
In Java, if we need to print values in a statement, we will use concatenation operator as −
System.out.println("At the age of "+23+" ramu got his first job");
这涉及将整数值 23 转换为字符串,并将该值连接到它周围的字符串。
This involves the conversion of the integer value 23 to string and concatenation of this value to the strings surrounding it.
如果这是一个日志语句,并且该语句的特定日志级别被禁用,则所有这些计算都将毫无用处。
And if it is a logging statement, and if that particular log level of your statement is disabled then, all this calculation will be of no use.
在这种情况,您可以使用参数化日志记录。在该格式中,SLF4J 最初确认是否启用了特定级别的日志记录。如果是,则它用各自的值替换消息中的占位符。
In such circumstances, you can use parameterized logging. In this format, initially SLF4J confirms whether the logging for particular level is enabled. If so then, it replaces the placeholders in the messages with the respective values.
例如,如果我们有一个语句,如
For example, if we have a statement as
Integer age;
Logger.debug("At the age of {} ramu got his first job", age);
只有在启用调试时,SLF4J 才会将年龄转换成整数,并在字符串连接它,否则它将不执行任何操作。因此,如果禁用日志记录级别,将导致参数构造成本。
Only if debugging is enabled then, SLF4J converts the age into integer and concatenates it with the strings otherwise, it does nothing. Thus incurring the cost of parameter constructions when logging level is disabled.
Two Argument Variant
您还可以在消息中使用两个参数,如下所示:
You can also use two parameters in a message as −
logger.info("Old weight is {}. new weight is {}.", oldWeight, newWeight);
Example
以下示例演示了带参数日志记录中两个占位符的用法。
The following example demonstrates the usage of two placeholders in parametrized logging.
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
执行后,上述程序生成以下输出。
Upon execution, the above program generates the following 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
您还可以使用多个占位符,如下面的示例所示:
You can also use more than two placeholders as shown in the following example −
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);
}
}
SLF4J - Migrator
如果您在 Jakarta Commons Logging (JCL) 或 log4j 或 java.util.logging (JUL) 中有一个项目,并且您希望将这些项目转换为 SLF4J,则可以使用 SLF4J 分发中提供的 migrator 工具来执行此操作。
If you have a project in Jakarta Commons Logging (JCL) or, log4j or, java.util.logging (JUL) and you want to convert these projects to SLF4J, you can do so using the migrator tool provided in the SLF4J distribution.
Running SLF4J Migrator
SLF4J 是一个简单的单 jar 文件 (slf4j-migrator.jar),并且您可以使用 java –jar 命令运行它。
SLF4J is a simple single jar file (slf4j-migrator.jar) and you can run it using the java –jar command.
若要运行它,在命令提示符中,浏览到存放此 jar 文件的目录并执行以下命令。
To run it, in command prompt, browse through the directory where you have this jar file and execute the following command.
java -jar slf4j-migrator-1.8.0-beta2.jar
Starting SLF4J Migrator
这将启动迁移程序,可看到独立的 Java 应用程序,如下所示:
This starts the migrator and you can see a standalone java application as −
如窗口中指定,您需要检查要执行的迁移类型,并选择项目目录,然后单击按钮“将项目迁移到 SLF4J”。
As specified in the window, you need to check the type of migration you want to do and select the project directory and click on the button Migrate Project to SLF4J.
该工具会转到您提供的源文件,并执行简单的修改,例如将导入行和记录器声明从当前日志记录框架更改为 SLF4j。
This tool goes to the source files you provide and performs simple modifications like changing the import lines and logger declarations from the current logging framework to SLF4j.
Example
例如,让我们假设我们有一个带一个文件的 log4j(2) 示例项目,如下所示:
For example, let us suppose we have a sample log4j(2) project in eclipse with a single file as follows −
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 进行迁移。
To migrate the sample log4j(2) project to slf4j, we need to check the radio button from log4j to slf4j and select the directory of the project and click Exit to migrate.
迁移程序将按如下方式更改上述代码。此处,如果您观察,import 和 logger 语句已经过修改。
The migrator changed the above code as follows. Here if you observe the import and logger statements have been modified.
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 和 slf4jlog12.jar 文件添加到项目中来执行它。
Since you already have log4j.jar in your project, you need to add slf4j-api.jar and slf4jlog12.jar files to the project to execute it.
Limitations of SLF4JMigrator
以下是 SLF4J 迁移程序的局限性。
Following are the limitations of the SLF4J migrator.
-
Migrator will not modify build scripts like ant, maven and, ivy you need to do it yourself.
-
Migrator does not support messages other than the String type.
-
Migrator does not support the FATAL level.
-
While working with log4j, migrator will not migrate calls to PropertyConfigurator or DomConfigurator.
SLF4J - Profiling
SLF4J 分发提供 slf4j-ext.jar 这里包含用于分析性能、扩展记录、事件记录和使用 Java 代理记录等功能的 API。
SLF4J Distribution provides slf4j-ext.jar this contains APIs for the functionalities such as profiling, Extended logging, Event logging and, logging with java agent.
Profiling
有时,程序员想要测量一些属性,如内存使用、时间复杂度或特定指令的使用,以测量该程序的实际能力。对此类程序的测量称为分析性能。分析性能使用动态程序分析进行测量。
Sometimes the programmer wants to measure some attributes like the use of memory, time complexity or usage of particular instructions about the programs to measure the real capability of that program. Such kind of measuring about the program is called profiling. Profiling uses dynamic program analysis to do such measuring.
SLF4J 提供名为 Profiler 的类,位于 org.slf4j.profiler 包中,用于性能分析。这被称为穷人的分析程序。使用此类,程序员可以找出执行较长时间任务所花费的时间。
SLF4J provides a class named Profiler in the org.slf4j.profiler package for profiling purpose. This is known as the poor man’s profiler. Using this, the programmer can find out the time taken to carry out prolonged tasks.
Profiling Using the Profiler class
分析性能包含秒表和子秒表,我们可以使用分析性能类提供的方法来启动和停止它们。
The profiler contains stopwatches and child stopwatches and we can start and stop these using the methods provided by the profiler class.
若要通过 Profiler 类继续进行分析,请按照以下步骤操作。
To carry on with profiling using the profiler class, follow the steps given below.
Step 1 - Instantiate the profiler class
通过传递表示分析器名称的 String 值来实例化 Profiler 类。实例化 Profiler 类时,将启动全局秒表。
Instantiate the Profiler class by passing a String value representing the name of the profiler. When we instantiate a Profiler class, a global stopwatch will be started.
//Creating a profiler
Profiler profiler = new Profiler("Sample");
Step 2 - Start a child stopwatch
调用 start() 方法时,将启动一个新的子秒表(命名),并停止较早的子秒表(或时间工具)。
When we invoke the start() method it will start a new child stopwatch (named) and, stops the earlier child stopwatches (or, time instruments).
通过传递表示要创建的子秒表名称的 String 值来调用 Profiler 类的 start() 方法。
Invoke the start() method of the Profiler class by passing a String value representing the name of the child stopwatch to be created.
//Starting a child stopwatch and stopping the previous one.
profiler.start("Task 1");
obj.demoMethod1();
创建这些秒表后,您可以执行您的任务或调用运行您任务的方法。
After creating these stopwatches, you can perform your tasks or, invoke those methods, which run your tasks.
Step 3: Start another child stopwatch (if you wish to)
如果您需要,请使用 start() 方法创建另一个秒表并执行所需的任务。如果您这样做,它将启动一个新的秒表并停止前一个秒表(即任务 1)。
If you need, create another stopwatch using the start() method and perform the required tasks. If you do so, it will start a new stop watch and stops the previous one (i.e. task 1).
//Starting another child stopwatch and stopping the previous one.
profiler.start("Task 2");
obj.demoMethod2();
Step 4: Stop the watches
当我们调用 stop() 方法时,它将停止最近的子秒表和全局秒表并返回当前时间工具。
When we invoke the stop() method, it will stop the recent child stopwatch and the global stopwatch and returns the current Time Instrument.
// Stopping the current child stopwatch and the global stopwatch.
TimeInstrument tm = profiler.stop();
Step 5: Print the contents of the time instrument.
使用 print() 方法打印当前时间工具的内容。
Print the contents of the current time instrument using the print() method.
//printing the contents of the time instrument
tm.print();
Example
以下示例演示了使用 SLF4J 的 Profiler 类的分析。这里我们取了两个示例任务,打印从 1 到 10000 的数字的平方和,打印从 1 到 10000 的数字的和。我们正尝试获得这两个任务所需的时间。
The following example demonstrates the profiling using Profiler class of SLF4J. Here we have taken two sample tasks, printing the sum of squares of the numbers from 1 to 10000, printing the sum of the numbers from 1 to 10000. We are trying to get the time taken for these two tasks.
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
执行后,上述程序生成以下输出 -
Upon execution, the above program generates the following 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
与其将分析器结果打印到日志中以记录此信息,您需要 -
Instead of printing the result of a profiler to log this information, you need to −
-
Create a logger using the LoggerFactory class.
-
Create a profiler by instantiating the Profiler class.
-
Associate the logger to profiler by passing the logger object created to the setLogger() method of the Profiler class.
-
Finally, instead of printing log the information of the profiler using the log() method.
Example
在以下示例中,与前一个示例不同(而非打印),我们尝试记录时间工具的内容。
In the following example, unlike the previous one (instead of printing), we are trying to log the contents of the time instrument.
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();
}
}