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:
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:
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:
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.