Boost Spring Boot Performance with Asynchronous Logback Logging

This article explains how to configure Logback in Spring Boot to separate logs by level, use asynchronous appenders to reduce I/O latency, and demonstrates a performance test showing a ten‑fold throughput increase, while also detailing the underlying async logging mechanism.

Programmer DD
Programmer DD
Programmer DD
Boost Spring Boot Performance with Asynchronous Logback Logging

01 What you will learn

Log output to files and classify logs by LEVEL into different files.

Reduce disk IO by asynchronous logging to improve performance.

Principles of asynchronous log output.

02 Logback configuration file (logback-spring.xml)

Spring Boot includes logback and slf4j dependencies, so you only need to write the configuration file. The framework automatically loads a file named logback-spring or logback from the classpath. Instead of storing all logs in a single growing file, separate error logs from other levels and rotate logs by time.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <property resource="logback.properties"/>
    <appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.SSS}] [%C] [%t] [%L] [%-5p] %m%n</pattern>
        </layout>
    </appender>
    <!-- INFO and higher (excluding ERROR) -->
    <appender name="INFO-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.SSS}] [%C] [%t] [%L] [%-5p] %m%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_INFO_HOME}/%d.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    <appender name="ERROR-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>[%d{yyyy-MM-dd' 'HH:mm:ss.SSS}] [%C] [%t] [%L] [%-5p] %m%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_ERROR_HOME}/%d.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    <root level="info">
        <appender-ref ref="CONSOLE-LOG"/>
        <appender-ref ref="INFO-LOG"/>
        <appender-ref ref="ERROR-LOG"/>
    </root>
</configuration>

03 Asynchronous logging with Logback

Replace the synchronous configuration with an AsyncAppender that references the original file appender. This offloads the actual I/O to a separate thread, eliminating the blocking disk write during the logging call.

<!-- Asynchronous output -->
<appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
    <!-- Do not discard logs; default discardingThreshold is 0 -->
    <discardingThreshold>0</discardingThreshold>
    <!-- Queue depth (default 256) can be tuned -->
    <queueSize>256</queueSize>
    <appender-ref ref="INFO-LOG"/>
</appender>

<appender name="ASYNC-ERROR" class="ch.qos.logback.classic.AsyncAppender">
    <discardingThreshold>0</discardingThreshold>
    <queueSize>256</queueSize>
    <appender-ref ref="ERROR-LOG"/>
</appender>

04 Performance test of asynchronous logging

Using Apache JMeter with 100 threads and a ramp‑up of 0, the synchronous configuration achieved a throughput of 44.2 requests per second (TPS). The asynchronous configuration reached 497.5 TPS, an improvement of more than ten times.

05 Asynchronous logging principle

When Logger.info is called, Logback creates a logging event that is placed into an ArrayBlockingQueue (default size 256). A dedicated worker thread in AsyncAppenderBase takes events from the queue and invokes appendLoopOnAppenders on each configured appender.

protected void append(E eventObject) {
    if (!this.isQueueBelowDiscardingThreshold() || !this.isDiscardable(eventObject)) {
        this.preprocess(eventObject);
        this.put(eventObject);
    }
}

The worker thread repeatedly executes:

E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);

Finally, the encode and write methods format the log message and write it to the underlying file or console.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performancelogbackasynchronous loggingspring-boot
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.