Performance Comparison and Usage Guide for Logback vs Log4j2 in Java Applications
This article compares the performance of Logback and Log4j2, presents benchmark results under various thread counts, explains their relationship with SLF4J, and provides step‑by‑step configuration and usage instructions for both frameworks in Spring Boot projects, including best practices and sample code.
1. Introduction
Logback and Log4j2 are widely used Java logging frameworks. In production environments the performance of the logging subsystem can affect overall system cost, especially for large companies that run massive workloads. Choosing the right framework and configuring it properly is therefore important.
Relationship between SLF4J, Log4j and Logback
SLF4J is a logging façade that defines a set of logging APIs. Logback and Log4j2 are concrete implementations of those APIs. In other words, SLF4J provides the abstraction, while Logback and Log4j2 provide the actual logging functionality.
Obtaining a Logger
Method 1 – Lombok (recommended)
@Slf4j
public class Main {}Method 2 – Direct usage
Use org.slf4j.LoggerFactory.getLogger(...) to obtain a logger instance, typically declared as:
private static final Logger LOG = LoggerFactory.getLogger(Main.class);2. Performance Test Comparison
Benchmark Results
The tests show two clear conclusions:
Log4j2 outperforms Logback by roughly a factor of two.
Increasing the number of logging threads improves throughput up to about twice the number of CPU cores, after which the gain plateaus.
Tips
Including method names and line numbers in log messages significantly reduces throughput. Removing line numbers can double Log4j2 performance in single‑threaded scenarios.
Test Environment
Hardware : AMD Ryzen 5 3600 (6‑core, 3.95 GHz), 32 GB DDR4 2666 MHz.
JVM : Semeru JDK 11.0.20, -Xms1000m -Xmx1000m .
Library Versions : Log4j 2.22.1, Logback 1.4.14.
Thread counts : 1, 8, 32, 128.
Test method : Warm‑up phase, then three runs; the average of the formal runs is recorded.
Log pattern (example):
<!-- Log4j2 pattern -->
<Property name="log.pattern">[%d{yyyyMMdd HH:mm:ss.SSS}] [%t] [%level{length=4}] %c{1.}:%L %msg%n</Property>
<!-- Logback pattern -->
<pattern>[%date{yyyyMMdd HH:mm:ss.SSS}] [%thread] [%-4level] %logger{5}:%line %msg%n</pattern>3. Usage Guide
3.1 Logback in a Spring Boot Project
Spring Boot uses Logback by default, so no additional configuration is required for a typical Spring Boot application. For non‑Spring projects you can add the following Maven 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 :
<?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">
<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>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>3.2 Log4j2 in a Spring Project
Spring Boot defaults to Logback, so you must exclude the default logging starter 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 . Sample configuration:
<?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" fileName="${file.err.filename}" filePattern="${file.err.pattern}" bufferedIO="true">
<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 rolling policies to prevent disks from filling up.
Standardize log format across services (e.g., timestamp, thread, level, logger, message).
Avoid logging method names or line numbers in high‑throughput paths, as they add noticeable overhead.
Ensure a uniform logging strategy company‑wide to simplify downstream ETL and analysis.
4. Appendices
4.1 Test Code
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\n", first - start, System.currentTimeMillis() - first);
}
private static void execute(int threadNum, int times) {
List
> 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); }
});
}
}4.2 References
Logback performance test: https://logback.qos.ch/performance.html
Log4j2 performance test: https://logging.apache.org/log4j/2.x/performance.html
Comparison article: https://zhuanlan.zhihu.com/p/472941897
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
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.