Java
Log4j
Async Logger
Logging
Programming

Creating log4j Async logger programmatically

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Creating an asynchronous Log4j 2 setup programmatically is useful when your application bootstraps logging dynamically or cannot rely on log4j2.xml. The main design choice is whether you want fully asynchronous loggers or just an asynchronous root or appender, because Log4j 2 supports both and they are configured differently.

Async Logger vs Async Appender

Log4j 2 offers two related but different features:

  • async loggers, which use the LMAX Disruptor-based async logging path
  • async appenders, which queue work in front of normal appenders

If you want the highest-throughput logging model, async loggers are usually the better fit. If you only need to decouple one appender from the caller thread, an async appender may be enough.

For async loggers, make sure the Disruptor dependency is present:

xml
1<dependencies>
2  <dependency>
3    <groupId>org.apache.logging.log4j</groupId>
4    <artifactId>log4j-api</artifactId>
5    <version>2.23.1</version>
6  </dependency>
7  <dependency>
8    <groupId>org.apache.logging.log4j</groupId>
9    <artifactId>log4j-core</artifactId>
10    <version>2.23.1</version>
11  </dependency>
12  <dependency>
13    <groupId>com.lmax</groupId>
14    <artifactId>disruptor</artifactId>
15    <version>3.4.4</version>
16  </dependency>
17</dependencies>

Programmatic Async Root Logger Configuration

Log4j 2 provides a configuration builder API that works well for code-driven setup. The following example creates a console appender and an async root logger entirely in Java:

java
1import org.apache.logging.log4j.Level;
2import org.apache.logging.log4j.LogManager;
3import org.apache.logging.log4j.Logger;
4import org.apache.logging.log4j.core.config.Configurator;
5import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
6import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
7import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
8import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
9
10public class AsyncLoggingDemo {
11    public static void main(String[] args) {
12        ConfigurationBuilder<BuiltConfiguration> builder =
13            ConfigurationBuilderFactory.newConfigurationBuilder();
14
15        builder.setConfigurationName("AsyncConfig");
16        builder.setStatusLevel(Level.WARN);
17
18        AppenderComponentBuilder console = builder
19            .newAppender("Console", "Console")
20            .addAttribute("target", "SYSTEM_OUT");
21
22        console.add(builder.newLayout("PatternLayout")
23            .addAttribute("pattern", "%d [%t] %-5level %logger - %msg%n"));
24
25        builder.add(console);
26        builder.add(builder.newAsyncRootLogger(Level.INFO)
27            .add(builder.newAppenderRef("Console")));
28
29        Configurator.initialize(builder.build());
30
31        Logger logger = LogManager.getLogger(AsyncLoggingDemo.class);
32        logger.info("Async logger is running");
33    }
34}

This creates an asynchronous root logger. All log events that propagate to the root are handled asynchronously.

Making All Loggers Asynchronous

If you want every logger in the context to use the async logger implementation, set the context selector before Log4j initializes.

java
1import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
2
3System.setProperty(
4    "log4j2.contextSelector",
5    AsyncLoggerContextSelector.class.getName()
6);

That system property must be set before the first logger is created. If any logger is obtained first, the context may already be initialized and the selector change will arrive too late.

A good startup pattern is:

  1. set the context selector system property
  2. build the configuration programmatically
  3. initialize Log4j
  4. obtain loggers

That ordering is important.

When an Async Appender Is Enough

Sometimes you do not need full async loggers. You only want to protect the application thread from a slow file or network appender. In that case, an async appender can be simpler and less invasive.

Programmatically, that means creating a normal appender first and then wrapping it in an async appender configuration. The logging call path still starts as a normal logger, but the expensive appender work is queued.

That option is useful in existing systems where changing the logger context selector would be too disruptive.

Programmatic Configuration Tips

When configuring Log4j 2 in code, keep these rules in mind:

  • initialize Log4j only once during startup
  • set async-related system properties before creating loggers
  • choose one approach consistently rather than mixing several async modes casually
  • shut down Log4j cleanly on application exit if the runtime is short-lived

A short-lived CLI tool that exits immediately after logging may appear to “lose” the last few messages if the process stops before the async pipeline flushes. Clean shutdown matters more with asynchronous logging than with synchronous console logging.

Common Pitfalls

The most common mistake is forgetting the Disruptor dependency. Without it, async logger features may fail or silently fall back depending on the exact setup.

Another issue is setting log4j2.contextSelector too late, after a logger has already been created.

Developers also often mix up async loggers and async appenders. They are related but not interchangeable.

Finally, asynchronous logging improves throughput, but it also changes failure and shutdown behavior. If the process crashes hard, the newest queued messages may not be written yet.

Summary

  • Log4j 2 supports both async loggers and async appenders.
  • Programmatic setup works well with the ConfigurationBuilder API.
  • Add the Disruptor dependency for async logger support.
  • Set log4j2.contextSelector before creating loggers if you want the full async logger context.
  • Use async logging deliberately, especially in short-lived processes or systems with strict shutdown requirements.

Course illustration
Course illustration

All Rights Reserved.