Registration is open - Live, Instructor-led Online Classes - Elasticsearch in March - Solr in April - OpenSearch in May. See all classes


Java Logging Frameworks Comparison: SLF4j vs Log4j vs Logback vs Log4j2 [Differences]

Any software application or a system can have bugs and issues in testing or production environments. Therefore, logging is essential to help troubleshoot issues easily and introduce fixes on time. However, logging is useful only if it provides the required information from the log messages without adversely impacting the system’s performance.

Traditionally, implementing logging that satisfies these criteria in Java applications was a tedious process. Developers had to rely on simple println statements to write logs to console. These days, developers can use various logging frameworks to solve these issues. The problem now has shifted to finding the one that satisfies their requirements.

This article compares the similarities and differences between the five most popular java logging frameworks – java.util.logging, Log4j, Logback, Log4j2, and SLF4j – to help you decide which is the right one for you.

java.util.logging vs SLF4j

The main difference between java.util.logging (JUL) and SLF4j (Simple Logging Facade for Java) is that SLF4j is not a logging framework but a framework that acts as an abstraction for other types of Java logging frameworks, including JUL.

JUL is the Java Development Kit’s (JDK) framework. It provides one of the simplest forms of logging but enables writing separate implementation logics for log output, which makes it more suitable for applications requiring less logging. JUL is also easier to use and comes with Java by default.

SLF4j lets you use the logging framework of your choice. You only have to provide the config, which defines the log level, log format, log output, etc., and your framework’s dependency. This enables applications to switch to any Java logging framework interchangeably without impacting its implementations or doing any changes. Due to this functionality, SLF4j makes applications independent of logging frameworks, providing more flexibility and portability for logging across any part of the system than JUL.

SLF4j also provides more advanced functionalities than JUL, like saving the log files in DB and log rotation. Because of this convenience and the many advanced features, SLF4j is currently the most popular Java logging framework.

Both of these frameworks are easy to use. For logging with SLF4j, you just have to instantiate a new Logger object by calling the getLogger() method. Then you can use a specific log level to write log messages.

Lets compare the direct JUL instantiation with JUL instatiation using SLF4j. If you were to use direct JUL instatiation, you need to import the JUL library. You can then call the methods associated with four severity levels through the logger object.

import java.util.logging.*;

public final class SimpleLogger {

  public static void main(String... args) {
    SimpleLogger thing = new SimpleLogger();
    thing.doSomething();
  }

public void doSomething() {
    logger.config("this is config");
    logger.info("this is info");
    logger.warning("this is a warning");
    logger.severe("this is severe");
  }

}

However, if you wanted to use JUL with SLF4j, you must specify the SLF4j dependency in the the POM.xml file of your Maven project.

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

Next, you will configure JUL for SLF4j. Here you specify the severity levels it should capture. The framework will the capture all the severity levels upwards of the severity level you set through java.util.logging.consolehandler property. You will also specify the format of the log message.

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

Finally, you can initiate JUL using SLF4j as specified in the example below.

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

public class MyClass {
  private static Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

  public static void doSomething() {
      LOGGER.info("a test message");
  }
}

Logback vs Log4j2 vs SLF4j

Logback, the successor of Log4j, holds many improvements over Log4j in terms of its performance and native support for SLF4j. Some of the major improvements over Log4j are auto-reloading config files, filtering capabilities and automatic removal of old log archival.

If you look at Logback, it comes with 3 core modules:

  • logback-core: This is the base module that lays the foundation required by the following two modules.
  • logback-classic: This module contains an improved version of Log4j and also natively implements the SLF4j API that lets you switch between Logback and other frameworks.
  • logback-access: This module integrates with servlet containers such as Tomcat and Jetty allowing HTTP-access log function.

Log4j2, on the other hand, is the successor of Logback and in addition to Logback’s features, offers advanced features like lazy evaluation of log messages based on lambda expressions, asynchronous loggers and an option to disable garbage-collector operations. For these reasons, developers will find Log4j2 to be more efficient and faster than Logback.

Both Logback and Log4j2 are popular among developers and can be directly used for logging. However, in directly using either of these frameworks, you will be locked to the framework throughout the development process. In the future, if you want to move to any other Java framework, you might need to make changes that span across multiple classes.

Suppose you had implemented Log4j framework directly with your library of 10000 classes using the following code:

import org.apache.log4j.Logger;

public class MyClass {
  private static Logger LOGGER = LoggerFactory.getLogger(MyClass.class.doSomething());

  public static void doSomething() {
      LOGGER.info("a test message");
  }
}

If you want to replace Log4j with the Log4j2 framework, you will have to add the following code to all the 10000 classes individually.

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class MyClass {
  private static Logger LOGGER = LogManager.getLogger(MyClass.class.doSomething());

  public static void doSomething() {
      LOGGER.info("a test message");
  }
}

But if you had used Log4j with SLF4j, the only thing you need to do is replace the JUL jar files with Log4j2 jar file without touching any of the source code.

Lets look at the implementation in detail. First, you declare the dependency by adding the following code to the POM.xml of your Maven project.

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.0</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.0</version>
  </dependency>
</dependencies>

Then you will configure Log4j2 for SLF4j. Here you specify the configuration for severity levels it should capture. You will also specify the format of the log message.

<Configuration status="info"> 
    <Appenders> 
        <File name="FILE" fileName="myjava_app.log"> 
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> 
        </File> 
    </Appenders> 
    <Loggers> 
        <Logger name="org.hibernate.SQL" level="DEBUG"> 
            <AppenderRef ref="FILE"/> 
        </Logger> 
        <Logger name="org.hibernate.type.descriptor.sql" level="TRACE"> 
            <AppenderRef ref="FILE"/> 
        </Logger> 
        <Root level="info"> 
            <AppenderRef ref="FILE"/> 
        </Root> 
    </Loggers> 
</Configuration>

Finally, you can initiate Log4j2 using SLF4j as specified in the example below.

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

public class MyClass {
  private static Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

  public static void doSomething() {
      LOGGER.info("a test message");
  }
}

Log4j vs Log4j2

Log4j is the open-source logging framework that provides fast logging capabilities for Java applications. It was the most popular Java logging framework until its end of life was announced in 2015. Log4j was highly configurable, letting you define the logging behavior at run time and directly log the outputs to various destinations like console, file and databases. It also provided great flexibility to logging by allowing control of the log format and log level of each output.

But as applications evolved, it became incompatible with old versions of Java and Log4j2 emerged as its better version. Log4j2 comes with many features that Log4j didn’t have.

  • Native support for SLF4j
  • Automatic reloading of logging configuration
  • Advanced filtering
  • Support for lambda expressions evaluation
  • Support for low latency systems
  • Option to disable garbage collector

Similarly, Log4j only supported configuration files in properties and XML formats, while Log4j2 supports configuration through XML, JSON, YAML, and configuration files/programmatic actions. In comparison to Log4j, Log4j2 has active community support. Log4j2 also executes locks at the lowest layer, which helps solve the deadlock problem.

Comparison Summary: JUL vs Log4j vs Logback vs Log4j2 vs SLF4j

The following table sums up the comparison between these Java logging frameworks.

Framework/
Criteria
JULLog4jLogbackLog4j2SLF4j
FlexibilityLess flexibleLess flexibleLess flexibleLess flexibleHighly Flexible. Can switch different logging frameworks
Ease of useSimple logging structure which is easy to use.Simple logging structure which is easy to use.If used directly, not as easy to use as JUL.
If used with SLF4j, it is easy to use.
If used directly, not as easy to use as JUL.
If used with SLF4j, it is easy to use.
Easy to use
PortabilityLess portableLess portableLess portableHigh portability compared with Log4jHigh portability
MaintenanceHighly maintainableLess maintainability as support for Log4j is discontinuedHighly maintainableHighly maintainableHighly maintainable
PopularityPopular among simple applicationsLess popularNot popular than Log4J2Highly popularHighly popular
Features
  • Available by default with Java
  • Simple to use
  • Configurable
  • Supports SLF4j
  • Supports Java exceptions
  • Thread safe
  • Supports multiple log destinations
  • Supports setting logging behaviour in runtime
  • Supports multiple severity levels
  • Native support for SLF4j
  • Automatic log rotation
  • Automatic configuration file reloading
  • Advanced filtering
  • Native support for SLF4j
  • Automatic reloading of logging configuration
  • Advanced filtering
  • Support for lambda expressions evaluation
  • Support for low latency systems
  • Option to disable garbage collector
  • Supports major logging frameworks
  • Easier to manage dependencies
  • Well documented

Apache Commons Logging

Apache Commons Logging, or JCL, is a Java-based logging package that acts as an abstraction, which lets you choose between different logging frameworks. You can think of it as an alternative to SLF4j. It offers support for several Java logging frameworks with log and wrapper implementations and consists of other tool kits. JCL provides a common-logging API with many logging frameworks, eliminating an application’s dependencies with specific logging implementations.

JCL supports logging frameworks, including JUL, Log4j, and logging tool kits like Avalon and LogKit. The best advantage of using JCL is its flexibility for Java applications and libraries. JCL also uses runtime discovery mechanism to find a logging implementation, which is based on dynamic binding approach.

However, JCL is plagued by classloading issues, making it harder to debug JCL issues. In addition, JCL API creates its own logger wrapper for every classloader in use within your application, which results in another issue – unexpected interactions between the framework’s API and JCL’s API. This results in larger number of bugs making the already hard debug process more harder.

Which Is the Best Java Logging Framework?

While Log4j and JUL provide basic logging capabilities for Java applications, Log4j2 and Logback provide more sophisticated logging functionalities.

If your application is a simple application that just needs a simple logging message, the best framework would be JUL, as it comes directly with the JDK and has all the necessary functionalities for easy logging.

However, for more sophisticated applications, simple logging is not enough. You must also consider the efficiency and other capabilities, like filtering and multi-threading of the frameworks, as most production systems generate a large number of log files daily.

If you’re interested in a robust logging system that is quick to implement, has a powerful log rotation mechanism and is fairly robust, Logback could be your best choice. That’s because it is vastly superior to Log4j in terms of its performance and many other features like auto-reloading of config files without impacting the code and automatic removal of old log archival.

If you want logging for a low latency system or systems that require faster logging, Log4j2 might be the best framework, due to its filtering capabilities and plugin architecture that help make the logging extensible with its logging and filters.

You might also want to try all the Java logging frameworks to work out the right one for you. In such a case, configuring the frameworks to work with SLF4j could be the best route as it allows you to use different frameworks interchangeably throughout the application.

This is particularly important for applications with multiple services and integrations, having support for switching to multiple logging frameworks is always essential. For such applications combining the SLF4j framework with Log4j2 or Logback might be the most proper option.

If you are interested to learn more about each Java logging framework, check out the following articles:

Why Is Java Logging Important?

Generally speaking, logging is important – whether it be Java logging or logging in any other language – to get all the relevant information to capture critical events and assist in debugging software systems errors.

But, Java logging matters because it helps to understand the run-time behavior of a system. Java applications are highly revered for their performance and logs can provide important information about performance and efficiency-based metrics, including the system’s behavior under a load.

Similarly, if you are building a Java application, it only makes more sense to implement native Java logging as they are optimized for performance and efficiency with Java applications. They can also leverage the complex functionalities provided by the Java libraries.

When done correctly, Java logging provides complete and informative logs that can be used for analytics and to derive insights that benefit businesses. If you want to learn more about how to get the most out of your logs, check out this Java logging best practices tutorial.

Shipping Java Logs with Sematext

Sematext Logs is a unified log management and monitoring solution that collects and analyzes log files from across your whole infrastructure. Without any further configuration, Sematext’s log and service auto-discovery allows you to automatically begin monitoring logs and forwarding them from both log files and containers directly through the user interface.

Sematext allows you to create custom dashboards that connect logs, metrics, and infrastructure data for real-time system visibility, as well as set up useful alerts to be warned before your users discover problems.

There are many ways of sending data to Sematext Logs, but the easiest would be to use Syslog and put your Log App’s write token as the appName (or syslog tag, depending on the format). For example with log4j2, you’d define an appender like:

<Syslog name="Syslog" host="logsene-syslog-receiver.sematext.com" port="514" protocol="TCP"
      format="RFC5424" appName="TOKEN_GOES_HERE" facility="LOCAL0" mdcId="mdc"  newLine="true"/>

If you want data more structured, you can send JSON messages or you can have existing messages parsed server-side via pipelines. JSON logging is easier to maintain down the line, but the configuration might be a little trickier (e.g. by using JsonLayout in log4j2).

Finally, if these logs are critical, we recommend using a log shipper like Logstash to send data to Sematext Logs. This way, the log shipper takes care of retrying, buffering and potentially any enrichment of your log events, as opposed to your application. As always, there’s a trade-off, and you can read more about it in this post on logging libraries vs log shippers.

Start the 14-day free trial and try Sematext Logs yourself! If you want to learn more about its features and how it works, watch the video below.

Conclusion

Java provides several frameworks to implement logging capabilities for Java-based applications like JUL, Logback, Log4j, and Log4j2 frameworks.

While you can always choose to implement them directly, it’s always recommended to use them with frameworks like SLF4j as they provide a robust abstraction, enabling you to switch between multiple logging frameworks easily. Because only you can decide what is the right framework for you, abstraction frameworks offer you the ability to test all the frameworks without affecting your source code.

Finding the Java logging framework that fits your use case is essential if you want to get the most out of your application logs. As well as capturing the right logs at the right time and shipping them to the right place – one of the best ways to do this is using a log management tool like Sematext Logs, specifically designed to facilitate log analysis for faster troubleshooting. Give Sematext a try!

Start Free Trial