Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Logging

A log is a record of what happened in the application: who created a post, which request failed and why. On a server it is the main way to understand what happened overnight. Spring Boot has already configured logging: the lines you saw at startup come from it. All that is left is to write your own messages there.

Your own logger

// src/main/java/com/example/blog/PostService.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
@Service
@Transactional(readOnly = true)
public class PostService {
 
    private static final Logger log = LoggerFactory.getLogger(PostService.class);
 
    // ...
 
    @Transactional
    public PostResponse create(NewPostRequest request, String username) {
        User author = users.findByUsername(username)
                .orElseThrow(() -> new IllegalArgumentException("Unknown author " + username));
        Post post = posts.save(new Post(request.title(), request.body(), author, Instant.now(clock)));
        log.info("Post {} created by {}", post.getId(), username);
        return PostResponse.from(post);
    }
}

SLF4J is the common logging interface in Java, and the lines are written by the Logback library that Spring Boot brought in. There is one logger per class. The {} braces in a message are placeholders for arguments, filled in order.

A log line

After a post is created you see:

2026-10-04T12:12:09.089+03:00  INFO 21540 --- [blog] [http-nio-8080-exec-5] com.example.blog.PostService             : Post 1 created by anna
PartMeaning
2026-10-04T12:12:09.089+03:00Time
INFOLevel
21540Process id
[blog]The application name from spring.application.name
[http-nio-8080-exec-5]The thread: here, an HTTP request thread
com.example.blog.PostServiceThe class that wrote the line

Levels

LevelWhat for
ERRORSomething broke, action needed
WARNSuspicious, but work goes on
INFOImportant events: startup, a post created
DEBUGDetails for debugging
TRACEVery detailed

By default INFO and above are printed. The level is changed per package or class:

# src/main/resources/application.yaml
logging:
  level:
    com.example.blog: debug
    org.hibernate.SQL: debug

The first line enables log.debug(...) in our code, the second shows Hibernate's SQL through the log — on a server that is better than show-sql, which prints past the log.

Logging to a file

On a server the lines must be kept. It is one setting — let's put it into the prod profile:

# src/main/resources/application-prod.yaml
logging:
  file:
    name: logs/blog.log

Lines go both to the console and to the logs/blog.log file. When the file reaches 10 MB, Spring Boot starts a new one and compresses the old ones into an archive.

Errors with an exception

log.error("Could not import post {}", externalId, ex);

If you pass an exception as the last argument, the whole stack trace goes into the log — without it you cannot find the cause from the log.

Common mistake

Do not write System.out.println and do not build the string yourself: log.debug("Post " + post + " created"). The first never reaches the log file and cannot be switched off by levels. The second builds the string even when DEBUG is off and wastes time. Use {} — SLF4J fills in the values only if the line will really be written.

Thanks for reading!

Donate to the site — we work hard for you.