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.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Performance Comparison and Usage Guide for Log4j2 vs Logback in Java

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 MHz

JVM information

JDK version: semeru-11.0.20 JVM parameters:

-Xms1000m -Xmx1000m

Log4j2 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.

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.

Performance TestingSpring Bootlogbacklog4j2java logging
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.