Master Spring Boot Logging: 12 Practical Guidelines for High‑Performance Apps

This article presents twelve concrete guidelines and code examples for configuring Spring Boot 3 logging—covering readability, level selection, structured JSON output, asynchronous handling, sensitive data masking, and log rotation—to help developers build observable, maintainable, and high‑performance backend services.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot Logging: 12 Practical Guidelines for High‑Performance Apps

1. Introduction

In the era of distributed systems and micro‑service architecture, the amount of log data generated by Spring Boot applications grows exponentially. Logs are not only the "black box" for troubleshooting, but also the core basis for system health monitoring, security auditing, and performance optimization. Improper log configuration in production often leads to storage explosion, sensitive data leakage, and missing debug information. This article summarizes twelve guidelines covering framework selection, level control, structured output, and performance optimization, helping developers build observable, maintainable, high‑performance logging systems.

2. Practical Cases

2.1 Readable Logs

Many developers think "logs are for troubleshooting", but who will actually read them? Most logs are ignored or only consulted when a problem occurs. When writing each log statement, imagine a colleague at 3 am searching through the sea of logs.

// Poor log example
log.info("Processing start");
// ... business logic ...
log.info("Processing end");

// Improved log
log.info("Start processing user payment request. userId={}, orderId={}, amount={}", userId, orderId, amount);
// ... business logic ...
log.info("User payment request completed. userId={}, orderId={}, result={}", userId, orderId, result);

2.2 Vague Advice: Don’t Just "Add More Logs"

Simply increasing log volume does not always solve problems; the content, level, and destination must be considered. Indiscriminate logging can drown valuable information. Example of a Java project generating 50 MB of logs in five minutes, consisting only of repetitive debug statements.

log.debug("Entering method A");
log.debug("Exiting method A");
log.debug("Entering method B");
log.debug("Exiting method B");
// ...

Each log line incurs storage, I/O, and reading costs.

2.3 User‑Centric vs Developer‑Centric Logs

Most logs are written from a developer’s perspective, e.g.

log.info("Data processing completed, preparing to add to cache.");

A business‑oriented log should include domain information:

log.info("User {}'s order {} status changed from {} to {}", userId, orderId, oldStatus, newStatus);

2.4 Misusing ERROR Level

Developers often log every caught exception as ERROR, even when the exception is an expected business scenario. Example of proper level selection:

try {
    // TODO
} catch (InvalidCredentialsException e) {
    // Expected business case – use INFO
    log.info("User {} login failed: incorrect password", username);
    return ...;
} catch (Exception e) {
    // Unexpected – use ERROR
    log.error("User {} encountered system exception during login: {}", username, e);
    return ...;
}

Guideline for levels:

ERROR – issues requiring manual intervention.

WARN – problems that may become ERROR if not addressed.

INFO – important business milestones.

DEBUG/TRACE – temporary troubleshooting, usually disabled in production.

2.5 Avoid Logging Inside Loops

// Bad practice
for (Item item : items) {
    logger.info("Processing item: {}", item); // thousands of lines
}

// Improved version
logger.info("Preparing to process {} items", items.size());
// processing logic
logger.info("Finished processing {} items. success={}, fail={}", items.size(), successCount, failCount);

2.6 Use Placeholders Instead of String Concatenation

// Wrong
log.debug("Processing user: " + user.getName() + ", ID: " + user.getId());

// Correct
log.debug("Processing user: {}, ID: {}", user.getName(), user.getId());

2.7 Handle Large Objects Carefully

// Dangerous
log.debug("User data: {}", user);

// Better
log.debug("User basic info: id={}, name={}, type={}", user.getId(), user.getName(), user.getType());

2.8 Sensitive Data Masking

Never log passwords, tokens, personal identifiers, etc. Use masking or dedicated utilities.

// Unsafe
log.info("User login: username={}, password={}", username, password);

// Safe
log.info("User login: username={}, password=****", username);
// Or
log.info("User info: {}", LogSensitiveUtils.mask(userInfo));

2.9 JSON Log Format

Add Logstash encoder dependency and configure Logback to output JSON.

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>8.0</version>
</dependency>
<appender name="TRACEX" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
Log output example
Log output example

2.10 Asynchronous Logging

Logging is I/O‑intensive. Asynchronous appenders reduce latency.

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="TRACEX"/>
    <queueSize>512</queueSize>
    <discardingThreshold>0</discardingThreshold>
    <includeCallerData>false</includeCallerData>
</appender>

2.11 High‑Concurrency Logging Strategies

Sampling: log detailed info for a small percentage of requests.

Batch logging: aggregate multiple entries into a single write.

Non‑blocking queues (e.g., Disruptor).

Increase buffer size to reduce disk flush frequency.

// Simple sampling
if (Math.random() < 0.01) { // 1% sample rate
    logger.info("Detailed request: request={}, headers={}", request, headers);
}

2.12 Log Rotation and Archiving

Log files cannot grow indefinitely; define a rotation policy.

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>app.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <maxFileSize>100MB</maxFileSize>
        <maxHistory>30</maxHistory>
        <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
        <pattern>%d %p %c{1} [%t] %m%n</pattern>
    </encoder>
</appender>
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.

loggingSpring Bootsecurity
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

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.