eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

Logging is a powerful aid for understanding and debugging a program’s run-time behavior. Logs capture and persist important data, making it available for analysis at any time.

In this tutorial, we discuss the most popular Java logging frameworks, Log4j 2 and Logback, along with their predecessor Log4j. In addition, we briefly touch on SLF4J, a logging facade that provides a common interface for different logging frameworks.

2. Enabling Logging

The logging frameworks discussed in our article share the notion of loggers, appenders, and layouts. Enabling logging inside the project follows three common steps:

  1. Adding needed libraries
  2. Configuration
  3. Placing log statements

The upcoming sections discuss the steps for each framework individually.

3. Log4j 2

Log4j 2 is a new and improved version of the Log4j logging framework. The most compelling improvement is the possibility of asynchronous logging.

Log4j 2 requires the following libraries:

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

The latest versions of log4j-api and log4j-core are available in the official documentation.

3.1. Configuration

Configuring Log4j 2 is based on the main configuration log4j2.xml file.

The first thing to configure is the appender, which determines where the log message is routed, for instance, to the console, a file, a socket, etc.

Log4j 2 provides many appenders for different use cases, which are documented on the official Log4j 2 site.

Let’s take a look at a simple config example:

<Configuration status="debug" name="baeldung" packages="">
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
        </Console>
    </Appenders>
</Configuration>

We can set a name for each appender; for example, use console instead of stdout.

The PatternLayout element determines how the message should look. In our example, the pattern is set based on the pattern param, where %d determines the date pattern, %p the log level output, %m the output of the logged message, and %n adds a new line symbol. More info about patterns can be found on the official Log4j 2 page. Finally, to enable an appender (or multiple), we need to add it to the <Loggers> section:

<Loggers> 
    <Root level="error">
        <AppenderRef ref="STDOUT"/>
    </Root>
</Loggers>

With this configuration in place, Log4j 2 can route log messages to the configured appenders according to the defined logging levels.

3.2. Logging to File

Sometimes, we may need to add logging to a file. For this, we can add fout logger to our configuration:

<Appenders>
    <File name="fout" fileName="baeldung.log" append="true">
        <PatternLayout>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
        </PatternLayout>
    </File>
</Appenders>

The File appender has several parameters that can be configured:

  • file – determines the file name of the log file
  • append – the default value for this param is true, meaning that by default, a File appender will append to an existing file and not truncate it
  • PatternLayout – defines the format of each log entry, as described in the previous section

In order to enable File Appender, we need to add it to the <Root> section:

<Root level="INFO">
    <AppenderRef ref="stdout" />
    <AppenderRef ref="fout"/>
</Root>

With this configuration in place, Log4j 2 can write log messages to both the console and the specified log file.

3.3. Asynchronous Logging

Log4j 2 supports asynchronous logging, which can make our application faster by letting log messages be processed in the background. There are two ways to enable it, and they work differently. Both methods need the LMAX Disruptor library, which we need to add to our pom.xml:

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>4.0.0</version>
</dependency>

Using <AsyncRoot>:

<AsyncRoot level="DEBUG">
    <AppenderRef ref="stdout" />
    <AppenderRef ref="fout"/>
</AsyncRoot>

Here’s the breakdown:

  • Only the loggers inside <AsyncRoot> become asynchronous
  • All other loggers stay synchronous
  • Useful if we want some loggers to be async and others to stay normal

Works the same way as the <Root> configuration but only affects loggers defined within <AsyncRoot>.

Using the system property:

-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

Log4j 2 provides two asynchronous context selectors. The AsyncLoggerContextSelector configures all loggers to operate asynchronously, while BasicAsyncLoggerContextSelector is intended for scenarios that require more fine-grained control over asynchronous behavior.

Using the AsyncLoggerContextSelector system property results in the following behavior:

  • Makes all loggers in our application asynchronous
  • Convenient for high-performance logging
  • It should not be used together with <AsyncRoot> or <AsyncLogger>, since it can create extra background threads
  • We can verify that asynchronous logging is enabled by checking the org.apache.logging.log4j2 -> AsyncDefault MBean in JConsole, which exposes details such as buffer size and event processing metrics

When using the system property, all loggers become asynchronous as long as the configuration uses the standard <Root> and <Logger> elements. In contrast, <AsyncRoot> and <AsyncLogger> are meant for cases where asynchronous and synchronous loggers need to be mixed. These two approaches should not be combined, as doing so creates two separate background logging threads.

Both methods use the LMAX Disruptor library, just as appenders and layouts to control where and how log messages are written.

We can, of course, read more about the configuration of the Log4j2 async logger and see some performance diagrams on the Log4j2 official page.

3.4. Usage

The following is a simple example that demonstrates the use of Log4j for logging:

public class Log4jExample {

    private static Logger logger = LogManager.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

After running, the application logs the following messages to both the console and file named baeldung.log:

2016-06-16 17:02:13 INFO  Info log message
2016-06-16 17:02:13 ERROR Error log message

Now, let’s explore what happens if we elevate the root log level to ERROR:

<level value="ERROR" />

Here’s what the output looks like:

2016-06-16 17:02:13 ERROR Error log message

As we can see, changing the log level to the upper parameter causes the messages with lower log levels not to be printed to appenders.

Method logger.error can also be used to log an exception that occurred:

try {
    // Here some exception can be thrown
} catch (Exception e) {
    logger.error("Error log message", throwable);
}

Our example above illustrates how log levels control which messages are emitted and how Log4j 2 can be used to record both simple messages and exceptions.

3.5. Package Level Configuration

Here, let’s assume that we need to show messages with the log level TRACE, for example, from a specific package such as com.baeldung.log4j2:

logger.trace("Trace log message");

For all other packages, we want to continue logging only INFO messages. Meanwhile, let’s keep in mind that TRACE is lower than the root log level INFO that we specified in the configuration.

To enable logging only for one of the packages, we need to add the following section before <Root> to our log4j2.xml:

<Logger name="com.baeldung.log4j2" level="debug">
    <AppenderRef ref="stdout"/>
</Logger>

This section enables logging for the com.baeldung.log4j package and our output will look like this:

2016-06-16 17:02:13 TRACE Trace log message
2016-06-16 17:02:13 DEBUG Debug log message
2016-06-16 17:02:13 INFO  Info log message
2016-06-16 17:02:13 ERROR Error log message

This approach makes it possible to increase logging detail for a specific package while keeping the rest of the application’s logging unchanged.

4. Logback

Logback is meant to be an improved version of Log4j, developed by the same developer who made Log4j. It also has many more features than Log4j, with many of them being introduced into Log4j 2 as well. For additional information, we can take a quick look at all of the advantages of Logback on the official site.

Let’s start by adding the following dependency to the pom.xml:

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

Let’s note that Logback 1.5.x requires JDK 11+.

This dependency transitively pulls in another two dependencies, the logback-core and slf4j-api. Notably, the latest version of Logback can be found on Maven Central.

4.1. Configuration

Let’s now have a look at an example of Logback configuration:

<configuration>
  # Console appender
  <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      # Pattern of log message for console appender
      <Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
    </layout>
  </appender>

  # File appender
  <appender name="fout" class="ch.qos.logback.core.FileAppender">
    <file>baeldung.log</file>
    <append>false</append>
    <encoder>
      # Pattern of log message for file appender
      <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</pattern>
    </encoder>
  </appender>

  # Override log level for specified package
  <logger name="com.baeldung.log4j" level="TRACE"/>

  <root level="INFO">
    <appender-ref ref="stdout" />
    <appender-ref ref="fout" />
  </root>
</configuration>

Logback uses SLF4J as an interface, so we need to import SLF4J’s Logger and LoggerFactory.

4.2. SLF4J

SLF4J provides a common interface and abstraction for most of the Java logging frameworks. It acts as a facade and provides a standardized API for accessing the underlying features of the logging framework.

Logback uses SLF4J as a native API for its functionality:

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

public class Log4jExample {

    private static Logger logger = LoggerFactory.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

The output remains the same as in previous examples.

5. Log4J

Finally, let’s have a look at the venerable Log4j logging framework.

Before we proceed, let’s keep in mind that Log4j 1.x has reached end of life and is no longer actively maintained. As a result, it does not receive security updates and is not recommended for new applications. For existing projects, migrating to Log4j 2 or Logback is strongly encouraged.

At this point, it’s outdated, but worth discussing as it lays the foundation for its more modern successors.

Many of the configuration details match those discussed in the Log4j 2 section.

5.1. Configuration

First, we need to add the Log4j library to our project’s pom.xml:

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

The latest version of Log4j is available on Maven Central.

Let’s take a look at an example of a simple Log4j configuration with only one console appender:

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration debug="false">

    <!--Console appender-->
    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" 
              value="%d{yyyy-MM-dd HH:mm:ss} %p %m%n" />
        </layout>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="stdout" />
    </root>

</log4j:configuration>

<log4j:configuration debug=”false”>, the open tag of the whole configuration, has the property debug. This property determines whether we want to add Log4j debug information to logs.

5.2. Usage

After we have added the Log4j library and configuration, we can use the logger in our code.

Let’s take a look at a simple example:

public class Log4jExample {
    private static Logger logger = Logger.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

This example demonstrates the basic usage of Log4j 1.x to write log messages at different levels.

6. Conclusion

In this article, we present simple examples of how to use different logging frameworks, such as Log4j, Log4j2, and Logback. It covers simple configuration examples for all of the mentioned frameworks.

The examples that accompany the article can be found over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)