SLF4J Understanding

Simple Logging Facade for Java (SLF4J) reduces the coupling between application and logging framework. It support various logging frameworks as bindings. In this article, I will explain what is SLF...

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

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