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| Part | Meaning |
|---|---|
2026-10-04T12:12:09.089+03:00 | Time |
INFO | Level |
21540 | Process id |
[blog] | The application name from spring.application.name |
[http-nio-8080-exec-5] | The thread: here, an HTTP request thread |
com.example.blog.PostService | The class that wrote the line |
Levels
| Level | What for |
|---|---|
ERROR | Something broke, action needed |
WARN | Suspicious, but work goes on |
INFO | Important events: startup, a post created |
DEBUG | Details for debugging |
TRACE | Very 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: debugThe 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.logLines 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.