Overview
Logging is an important part of an application. Today, I would like to share my understanding about the Simple Logging Facade for Java (SLF4J). After reading this article, you will understand:
- What is SLF4J
- Why using SLF4J
- How to use it
- Choose the binding
The Simple Logging Facade for Java (SLF4J) is a simple facade for logging frameworks. It allows you to log events from your client code, without knowing the actual implementation of the logging system. The underlying logging backend is determined at runtime by adding the desired binding to the classpath.
Client --> SLF4J API --> SLF4J Impl
Why using SLF4J
Loose coupling. The separation of the client API from the logging framework reduces the coupling between an application and any particular logging framework. It makes integration easier with projects or third-party code that have already chosen their own logging backend.
Rich binding choices. There’re multiple implementation (binding)
choices: Java logging package (java.util.logging
), Log4J, No Operation (NOP),
Simple, Jakarta Commons Logging, and Logback. You can choose the one you want at
deployment time. More detail will be described in the binding section.
Popularity. In 2016, SLF4J API (slf4j-api
) is the 2nd of the most popular
Java frameworks based on OverOps’s
analysis
on GitHub.
SLF4J Demo
In this section, we will see how to use SLF4J in your source code. If you’re using Maven, you need to include the SLF4J API as dependency:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
Then, in the source code, you need to create a logger from Logger Factory
(LoggerFactory
). After that, you can log the desired messages.
org.slf4j.Logger
provides multiple log methods based on log levels: trace,
debug, info, warn, and error. You can log a simple Java string, or a format
string with arguments, or an exception (throwable). Here’s an example using a
format string, where the user is injected as an argument.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyService {
private static final Logger logger =
LoggerFactory.getLogger(MyService.class);
public void sayHi(String user) {
logger.info("Hi, {}", user);
}
}
The placeholder {}
is something special in SLF4J. It is also called
“parameterized message”. It provides a fast way of logging: if the log statement
is disabled, the value will not be evaluated. It’s equivalent to log statement
surrounded by if-statement, but in a less verbose way. It is at least 30 times
faster in case of disabled logging statement, according to SLF4J
FAQ.
// 1. No evaluation
logger.info("Hi, " + user);
// 2. Evaluation
if (logger.isInfoEnabled()) {
logger.info("Hi, " + user);
}
// 3. Smart evaluation (SLF4J)
// (30x faster than N.1)
logger.info("Hi, {}", user);
Choosing Binding
SLF4J supports various logging frameworks. The SLF4J distribution provides several JAR files as “SLF4J bindings”, with each binding corresponding to one supported framework.
Simple Logger (slf4j-simple
). Binding for Simple implementation, which
outputs all events to System.err
. Only messages of level INFO and higher are
printed. This binding may be useful in the context of small applications.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.26</version>
</dependency>
Log4J Logger (slf4j-log4j12
). Binding for log4j version 1.2, a widely used logging
framework. You also need to place log4j.jar on your class path.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
</dependency>
JDK Logger (slf4j-jdk14
). Binding for java.util.logging
, also referred
to as JDK 1.4 logging.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.26</version>
</dependency>
Jakarta Commons Logging (slf4j-jcl
). Binding for Jakarta Commons Logging.
This binding will delegate all SLF4J logging to JCL.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jcl</artifactId>
<version>1.7.26</version>
</dependency>
Logback Logging (logback-classic
and logback-core
). There are also SLF4J
bindings external to the SLF4J project, e.g. logback which implements SLF4J
natively. Logback’s ch.qos.logback.classic.Logger class is a direct
implementation of SLF4J’s org.slf4j.Logger interface. Thus, using SLF4J in
conjunction with logback involves strictly zero memory and computational
overhead.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
Note that I didn’t test these solutions myself. They’re referenced from DZone - Java Zone. Please let me know if you have troubles using these dependencies.
From SLF4J Manual, there’s graphical illustration of the general idea about the concrete bindings. I found it very useful and straight forward:
Concrete bindings of SLF4J
Conclusion
In this article, we learnt the basic about the Simple Logging Facade for Java (SLF4J), the motivation of using this framework (loose coupling and multiple bindings), how to use it in the source code, and finally, the possible bindings for the API. Hope you enjoy this article, see you the next time!
References
- Henn Idan, “The Top 100 Java Libraries in 2016”, OverOps Blog, 2016. https://blog.overops.com/the-top-100-java-libraries-in-2016-after-analyzing-47251-dependencies/
- “SLF4J - Logger Performance”, SLF4J, 2019. https://www.slf4j.org/faq.html#logging_performance
- “SLF4J - Manual”, SLF4J, SLF4J, 2019. https://www.slf4j.org/manual.html
- “SLF4J”, Wikipedia, 2019. https://en.wikipedia.org/wiki/SLF4J
- Zemian Deng, “How to Configure SLF4J with Different Logger Implementations”, DZone - Java Zone, 2013. https://dzone.com/articles/how-configure-slf4j-different