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 -Xmx1000mLog4j2 and Logback versions
<log4j.version>2.22.1</log4j.version>
<logback.version>1.4.14</logback.version>Test thread counts and method
Thread numbers: 1, 8, 32, 128
Method: warm‑up, run three times, take average of formal runs.
Log format
<!-- log4j2 configuration -->
<Property name="log.pattern">[%d{yyyyMMdd HH:mm:ss.SSS}] [%t] [%level{length=4}] %c{1.}:%L %msg%n</Property>
<!-- logback configuration -->
<pattern>[%date{yyyyMMdd HH:mm:ss.SSS}] [%thread] [%-4level] %logger{5}:%line %msg%n</pattern>Log 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.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>Sample configuration file (logback.xml) shown.
<?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>2. Using Log4j2 in Spring
Exclude Spring Boot’s default logging and add Log4j2 dependencies, then place src/main/resources/log4j2.xml.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
... (other dependencies)Sample log4j2 configuration shown.
<?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 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
", 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);
}
});
}
} <!-- Maven pom.xml snippet -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.winjeg.spring</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<log4j.version>2.22.1</log4j.version>
<logback.version>1.4.14</logback.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<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>
</dependencies>
</project>References
Logback official performance results.
Log4j2 official performance results.
Article comparing log4j, logback, and 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.
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.
