Boost Spring Boot Performance: Master Logback Async Logging & File Separation

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

Programmer DD
Programmer DD
Programmer DD
Boost Spring Boot Performance: Master Logback Async Logging & File Separation

Logback Configuration and Asynchronous Logging in Spring Boot

Spring Boot includes Logback and SLF4J by default, so you only need to create a configuration file without adding extra dependencies.

Logback automatically loads a file named logback-spring.xml or logback.xml from the classpath. Storing all logs in a single file makes the file grow indefinitely and hampers troubleshooting; the proper approach is to separate error logs from other logs and rotate them 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>
    <!-- Get logs higher than INFO (including INFO) but exclude 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>

Key Tags Explanation

<root>

– required tag that sets the base logging level. <appender> – defines an appender; the name attribute gives it a name, and the class attribute selects the output strategy (e.g., ConsoleAppender for console, RollingFileAppender for file). <filter> – specifies a filtering strategy, such as LevelFilter or ThresholdFilter. <encoder> – defines the log output format. <rollingPolicy> – configures log rotation, for example time‑based rolling with a file name pattern and a retention period.

Asynchronous Logging

Traditional logging is synchronous; each log write incurs a disk I/O operation that blocks the thread. By adding an asynchronous appender that forwards logs to an existing appender, the logging work is off‑loaded to a separate worker thread, eliminating the I/O block in the main thread.

<!-- Async output -->
<appender name="ASYNC-INFO" class="ch.qos.logback.classic.AsyncAppender">
    <discardingThreshold>0</discardingThreshold>
    <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>

Performance Test

Hardware: 6‑core CPU, 8 GB RAM. Tool: Apache JMeter.

Synchronous logging test (100 threads, ramp‑up 0) yielded a throughput of 44.2 requests per second.

Synchronous logging throughput
Synchronous logging throughput

Asynchronous logging test (same load) produced a throughput of 497.5 requests per second, more than ten times higher.

Asynchronous logging throughput
Asynchronous logging throughput

How Asynchronous Logging Works

When Logger.info(...) is called, the event is passed to AsyncAppenderBase.append(). If the queue is not beyond the discarding threshold, the event is pre‑processed and placed into a blocking queue (default ArrayBlockingQueue size 256). A dedicated worker thread takes events from the queue and invokes appendLoopOnAppenders, which encodes the event and writes it to the target file.

protected void append(E eventObject) {
    if (!this.isQueueBelowDiscardingThreshold() || !this.isDiscardable(eventObject)) {
        this.preprocess(eventObject);
        this.put(eventObject);
    }
}
E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);

The main thread continues execution after enqueuing the log event, while the worker thread handles the actual I/O.

Reference

https://github.com/TiantianUpup/springboot-log
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.

JavaBackend DevelopmentPerformance TestingSpring Bootlogbackasynchronous logging
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.