Spring Boot Logging

Logging records what an application does while it runs. Each log line carries a time, a severity level, and a message. Developers read these lines to find bugs, track user actions, and confirm that features work as planned.

Spring Boot includes a ready logging system. A new project prints neat log lines to the console on the very first run, with no setup at all.

The Black Box Idea

Every airplane carries a flight recorder. The device notes speed, altitude, and warnings during the journey. Investigators study the recording after a problem and learn exactly what happened. A log file plays the same role for software. When a customer reports a failed payment at 2:15 PM, the developer opens the log and reads the events from that minute.

 Application running
    |
    +--> 10:00:01 INFO  User logged in
    +--> 10:00:05 INFO  Order 501 created
    +--> 10:00:09 ERROR Payment gateway timeout
    |
 [ Log file ] --> Developer reads --> Problem found

Default Setup

Spring Boot uses SLF4J as the logging interface and Logback as the engine behind it. SLF4J gives developers one simple set of commands. Logback handles formatting and output. Swapping Logback for another engine later needs no change in application code.

Log Levels

Levels rank messages by importance. A level setting acts as a filter: the application prints messages at that level and above.

LevelMeaningExample
TRACEFinest detailEntering a method
DEBUGDeveloper diagnosticsValue of a variable
INFONormal eventsServer started
WARNUnexpected but harmlessRetry attempt used
ERRORFailure that needs attentionDatabase unreachable
 TRACE < DEBUG < INFO < WARN < ERROR
 Level set to INFO  -->  prints INFO, WARN, ERROR

Spring Boot defaults to INFO. Debug and trace messages stay hidden until a developer lowers the level.

Writing Log Messages

Create one logger per class with the LoggerFactory. Placeholders written as curly braces insert values into the message.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class OrderService {

    private static final Logger log = LoggerFactory.getLogger(OrderService.class);

    public void placeOrder(Long orderId) {
        log.info("Order {} received", orderId);
        try {
            // business logic
        } catch (Exception e) {
            log.error("Order {} failed", orderId, e);
        }
    }
}

Placeholders beat string joining, because the message text builds only when the level is active. Passing the exception object as the final argument prints the full stack trace.

Changing Levels in Properties

The application.properties file controls levels without touching code.

logging.level.root=INFO
logging.level.com.estudy.shop=DEBUG
logging.level.org.hibernate.SQL=DEBUG

The first line sets the global level. The second raises detail for one package. The third reveals the SQL statements that Hibernate sends to the database.

Writing Logs to a File

Console output disappears when the window closes. File output keeps a permanent record.

logging.file.name=logs/shop.log
logging.logback.rollingpolicy.max-file-size=10MB
logging.logback.rollingpolicy.max-history=7

The rolling policy starts a new file when the current one reaches 10 MB and deletes files older than seven days. The disk never fills with old logs.

Custom Line Format

logging.pattern.console=%d{HH:mm:ss} %-5level %logger{20} - %msg%n

The pattern prints the time, the level, a shortened class name, and the message.

Levels per Profile

Profiles let one project log differently in each environment. A development profile prints debug detail. A production profile keeps only warnings and errors.

# application-dev.properties
logging.level.root=DEBUG

# application-prod.properties
logging.level.root=WARN

What to Keep Out of Logs

Logs often reach many people, including support teams and monitoring tools. Protect users by never writing passwords, card numbers, tokens, or personal details into a log line. Mask or skip sensitive values before logging.

Best Practices

  • Use INFO for business milestones and ERROR for real failures.
  • Write messages that name the item involved, such as an order number.
  • Avoid log statements inside tight loops.
  • Replace System.out.println with a logger in every class.
  • Review log size regularly and keep the rolling policy active.

Good logging shortens the time between a problem and its fix. A team that logs clearly spends less effort guessing and more effort solving.