Getting Started with Simple Logging Facade (SLF4J)

Simple Logging Facade for Java (SLF4J) is a logging facade that provides a unified interface for various logging frameworks, such as log4j, java.util.logging, and Logback. It allows for the decoupling of the application code from the underlying logging framework, making it easier to change the logging framework without modifying the application code. Here is a small tutorial to discuss the advantages of using SLF4J versus direct logging configuration.

SLF4J acts as an abstraction layer for different logging frameworks, such as java.util.logging, logback, and log4j, allowing the user to choose their preferred framework at the time of deployment, without modifying the application code.

There are several advantages in this approach. For example:

  • Flexibility: SLF4J allows you to switch between different logging frameworks without modifying the application code. This means you can start using log4j and later switch to logback or java.util.logging without changing the application code. It also allows you to use multiple logging frameworks at the same time.
  • Better integration: SLF4J allows for easy integration with other libraries, allowing you to use a common logging facade across your entire application, making it easier to understand and troubleshoot your logs.

Within this article, we will show a simple SLF4J project for a Java standalone application. If you would like to use SLF4J in a managed environment such as WildFly or JBoss EAP, check this article: How to configure SLF4J in WildFly applications

SLF4J in Action

Firstly, we will build a “vanilla” example of an application which uses SLF4J for printing log messages.

Add the following Class to your project:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {

  // Create a logger
  private static final Logger logger = LoggerFactory.getLogger(App.class);

  public static void main(String[] args) {

    // Log a debug message
    logger.debug("This is a debug message");

    // Log an info message
    logger.info("This is an info message");

    // Log a warning message
    logger.warn("This is a warning message");

    // Log a error message
    logger.error("This is an error message");
    

  }
}

This class uses the org.slf4j.Logger to print a set of messages on the Console.

Next, we will need to add the API dependency so that we can build the Class. Also, we need to add a Logging provider which will handle the Log Messages. Add the following dependency in your project:

<!-- API --> 
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.6</version>
</dependency>

<!-- SLF4J Provider -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.6</version>
</dependency>

SLF4J: No SLF4J providers were found

If you fail to include a Logging Provider in your project, SLF4J will issue the warning: “No SLF4J providers were found.SLF4J: Defaulting to no-operation (NOP) logger implementation.”

Then, you can run the main Class and check that Log messages display om the console:

slf4j tutorial

Using Parameters in your Log Messages

One of the advantages of using SLF4J is the ability to create parameterized log messages efficiently. For example:

int errorCode=15;
String errorMSG="ERR0015";
// Log an error message
logger.error("Hit the error-code {} and error-message {}", errorCode, errorMSG);

This is similar to the String.format method, but with an important difference. When using parameterized methods, the parameter construction will not happen if the log statement is disabled.

Switching to another Logging Provider

We will now show the real advantage of using SLF4J. That is, you can use the same Logging API which SLF4J even if you change the Logging Provider.

Using Log4j2 as Logging Provider

To use Log4j2 in your project, simply include the following dependency in your project:

<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-slf4j-impl</artifactId>
   <version>2.9.0</version>
</dependency>

When you include the Logging Provider for Log4j2 (log4j-slf4j-impl), Maven will automatically pull the transitive dependencies for SLF4J in your Project:

$ mvn dependency:tree
[INFO] Scanning for projects...
. . . .
[INFO] \- org.apache.logging.log4j:log4j-slf4j-impl:jar:2.9.0:compile
[INFO]    +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO]    +- org.apache.logging.log4j:log4j-api:jar:2.9.0:compile
[INFO]    \- org.apache.logging.log4j:log4j-core:jar:2.9.0:runtime

Therefore, you don’t need to specify explicitly the slf4j-api in your project.

Next, add a Log4j2 configuration file in the classpath. For example, add in the resources folder the following log4j2.xml :

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="[Log4j]%d{HH:mm:ss.SSS} %-5level - %msg%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Finally, run the application and check that the PatternLayout matches with your Log4j2 configuration:

SLF4J tutorial

Using LogBack as Provider

LogBack is designed to be faster than other logging frameworks such as log4j. It uses a faster and more efficient I/O system, which can greatly improve the performance of an application that generates a large number of log messages.

To use LogBack in your project, simply include the following dependency in your project:

<dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>1.3.5</version>
</dependency>

Note: If you are integrating LogBack with Jakarta EE, then you need to use the version 1.4.5 or newer of Logback.

Also in this case, Maven will automatically pull the transitive dependencies for SLF4J in your Project. Finally, include a logback.xml configuration file in the resources folder:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[LogBack]%d{yyyy-MM-dd HH:mm:ss:SSS} %5p %t %c{2}:%L - %m%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="stdout"/>
    </root>
</configuration>

Finally, verify that the application logs according to LogBack configuration:

SLF4J example tutorial

Using JUL as Logging Provider

Finally, we will show how to use Java Util Logging (JUL) as a logging implementation for SLF4J. To do that, include the following dependency:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>2.0.6</version>
</dependency>

Here is a sample jul-log.properties that you can add in the resources folder of your application:

handlers= java.util.logging.ConsoleHandler
.level= INFO
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%4$s] %5$s %n

Conclusion

In conclusion, Simple Logging Facade for Java (SLF4J) is a powerful logging facade that provides a unified interface for various logging frameworks. It allows for the decoupling of the application code from the underlying logging framework, making it easier to change the logging framework without modifying the application code. The advantages of using SLF4J include flexibility, better performance, portability, better maintenance, better testing, and better integration.

Found the article helpful? if so please follow us on Socials