logback vs log4j2: Up to Double the Performance—Why It Matters
A benchmark shows log4j2 can be roughly twice as fast as logback, especially when thread count approaches twice the CPU cores, while logging method names and line numbers significantly degrade throughput; the article explains the underlying reasons, testing setup, and provides practical configuration and usage guidelines for both frameworks in Java and Spring projects.
Introduction
logback and log4j2 are popular Java logging frameworks. Performance differences can be significant in large‑scale production environments.
Relationship with SLF4J
SLF4J is a logging façade; logback and log4j2 are concrete implementations of its APIs.
Obtaining a Logger
Two common ways:
Method 1: Using Lombok (recommended)
@Slf4j
public class Main {}Method 2: Direct SLF4J usage
private static final Logger LOG = LoggerFactory.getLogger(Main.class);Performance Test Comparison
Test Environment
CPU: AMD Ryzen 5 3600 6‑Core (3.95 GHz)
Memory: 32 GB 2666 MHz
JDK: semeru‑11.0.20
JVM options: -Xms1000m -Xmx1000m
log4j2 version: 2.22.1
logback version: 1.4.14
Thread counts: 1, 8, 32, 128
Test method: warm‑up, then three runs, averaging the formal run
Log pattern length: ~129 characters
Results
log4j2 outperforms logback; its throughput is roughly twice that of logback.
Throughput peaks when the number of threads is about twice the CPU core count; it does not increase linearly with thread count.
Tip: Enabling method name and line number in the log pattern dramatically reduces performance. Removing the line number alone can make log4j2 more than twice as fast in single‑threaded tests.
Performance chart:
Additional chart:
Usage in Projects
logback in Spring Boot
Add the dependency and place logback.xml under src/main/resources:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>Sample logback.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<file>log/output.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>log/output.log.%i</fileNamePattern>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>1MB</MaxFileSize>
</triggeringPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>log4j2 in Spring (non‑Spring‑Boot) Projects
Exclude Spring Boot’s default logback and add log4j2 dependencies:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>${log4j.version}</version>
</dependency>Place log4j2.xml under src/main/resources:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Properties>
<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
<Property name="file.err.filename">log/err.log</Property>
<Property name="file.err.pattern">log/err.%i.log.gz</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${log.pattern}"/>
</Console>
<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
<PatternLayout pattern="${log.pattern}"/>
<Policies>
<SizeBasedTriggeringPolicy size="1 MB"/>
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="console" level="info"/>
<AppenderRef ref="err" level="error"/>
</Root>
</Loggers>
</Configuration>Best Practices
Configure log rotation (maximum file count and size) to prevent disks from filling up.
Standardize log format (e.g., method name first, then parameters) and implement meaningful toString() for objects.
Avoid expensive pattern elements such as method name and line number unless required, as they add noticeable overhead.
Test Code Example
package com.winjeg.demo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@Slf4j
public class Main {
private static final Logger LOG = LoggerFactory.getLogger(Main.class);
private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
128, 256, 1L, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(512),
new BasicThreadFactory.Builder().namingPattern("thread-%d").daemon(true).build());
public static void main(String[] args) {
long start = System.currentTimeMillis();
execute(8, 160_000);
long first = System.currentTimeMillis();
execute(8, 160_000);
System.out.printf("time cost, preheat:%d\t, formal:%d
", first - start, System.currentTimeMillis() - first);
}
private static void execute(int threadNum, int times) {
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < threadNum; i++) {
Future<?> f = EXECUTOR.submit(() -> {
for (long j = 0; j < times; j++) {
LOG.info("main - info level ...this is a demo script, pure string log will be used!");
}
});
futures.add(f);
}
futures.forEach(f -> {
try { f.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); }
});
}
}References
logback official benchmark results
log4j2 official benchmark results
Java logging comparison article (log4j vs logback vs log4j2)
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Handbook
Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
