Performance Comparison and Usage Guide for Log4j2 vs Logback in Java
This article compares the performance of Log4j2 and Logback in Java, explains their relationship with SLF4J, presents benchmark results under various thread counts, and provides detailed configuration and usage guidelines for both Spring Boot and plain Java projects.
Introduction
logback, log4j2 and other logging frameworks are widely used in Java. Although developers rarely consider performance differences, these frameworks can have significant impact on cost in production environments, especially for large companies.
Choosing the right logging framework is important for performance and for standardizing log format for downstream ETL processes.
Relationship between SLF4J, Log4j, Logback
SLF4J is a logging facade providing a common API; Log4j and Logback are concrete implementations of that API.
Typical usage involves obtaining a Logger via LoggerFactory.getLogger(...) . Two ways are shown:
Method 1: Using Lombok (recommended)
@Slf4j
public class Main {}Method 2: Direct usage
Use org.slf4j.LoggerFactory.getLogger(...) and declare the logger as private static final Logger LOG = LoggerFactory.getLogger(Main.class);
Performance Test Comparison
Performance chart
Image omitted.
log4j2 outperforms logback, roughly twice as fast.
Log throughput does not increase linearly with thread count; performance peaks around twice the number of CPU cores.
Tips: Including method name and line number in log messages significantly reduces performance; removing line numbers can double log4j2 speed in single‑threaded tests.
Additional chart omitted.
Test Environment
Hardware
CPU AMD Ryzen 5 3600 6‑Core Processor Base speed: 3.95 GHz
Memory 32.0 GB Speed: 2666 MHzJVM information
JDK version: semeru-11.0.20
JVM parameters: -Xms1000m -Xmx1000m
Log4j2 and Logback versions
2.22.1
1.4.14Test thread counts and method
Thread numbers: 1, 8, 32, 128
Method: warm‑up, run three times, take average of formal runs.
Log format
[%d{yyyyMMdd HH:mm:ss.SSS}] [%t] [%level{length=4}] %c{1.}:%L %msg%n
[%date{yyyyMMdd HH:mm:ss.SSS}] [%thread] [%-4level] %logger{5}:%line %msg%nLog length
Approximately 129 characters per line, identical for both frameworks.
[20240125 16:24:27.716] [thread-3] [INFO] c.w.d.Main:32 main - info level ...this is a demo script, pure string log will be used!
[20240125 16:24:27.716] [thread-1] [INFO] c.w.d.Main:32 main - info level ...this is a demo script, pure string log will be used!Usage Guide
1. Using Logback in Spring Boot
Add the logback dependency (Spring Boot includes it by default) and place src/main/resources/logback.xml with appropriate configuration.
ch.qos.logback
logback-classic
${logback.version}Sample configuration file (logback.xml) shown.
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
log/output.log
log/output.log.%i
1MB2. Using Log4j2 in Spring
Exclude Spring Boot’s default logging and add Log4j2 dependencies, then place src/main/resources/log4j2.xml .
org.apache.logging.log4j
log4j-core
${log4j.version}
... (other dependencies)Sample log4j2 configuration shown.
%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n
log/err.log
log/err.%i.log.gzBest Practices
Configure log rotation to avoid disk exhaustion.
Standardize log format (e.g., method name then parameters) and implement meaningful toString methods.
Minimize expensive logging information such as method name and line number.
Adopt a unified logging convention across the organization for easier collection and analysis.
Appendix
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.0.0
com.winjeg.spring
demo
1.0-SNAPSHOT
jar
UTF-8
2.22.1
1.4.14
1.8
org.projectlombok
lombok
1.18.30
org.apache.commons
commons-lang3
3.12.0
org.apache.logging.log4j
log4j-core
${log4j.version}
org.apache.logging.log4j
log4j-api
${log4j.version}
org.apache.logging.log4j
log4j-slf4j2-impl
${log4j.version}References
Logback official performance results.
Log4j2 official performance results.
Article comparing log4j, logback, and log4j2.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.