Log khởi động Spring Boot là thứ bạn nhìn hàng ngày mà ít khi đọc kỹ. Bài này đi qua từng dòng.

Log thật

  Starting App v1.0 using Java 21.0.11 with PID 101 (/w/demo/target/demo-1.0.jar started by root in /w/demo)
  No active profile set, falling back to 1 default profile: "default"
  Tomcat initialized with port 8080 (http)
  Starting service [Tomcat]
  Starting Servlet engine: [Apache Tomcat/10.1.30]
  Root WebApplicationContext: initialization completed in 611 ms
  Exposing 8 endpoints beneath base path '/actuator'
  Tomcat started on port 8080 (http) with context path '/'
  Started App in 1.138 seconds (process running for 1.36)

Bốn dòng trả lời được hầu hết câu hỏi khi có sự cố.

Starting App v1.0 using Java 21.0.11 with PID 101 — phiên bản ứng dụng, phiên bản Java, và PID. PID là thứ bạn cần cho jstack, jcmd, jmap — bài 88 sê-ri Java.

No active profile set, falling back to "default" — dòng tôi kiểm đầu tiên khi cấu hình "không chịu áp dụng". Nếu bạn mong prod mà thấy default, vấn đề nằm ở cách truyền profile chứ không ở tệp cấu hình.

Tomcat started on port 8080 with context path '/' — cổng thật và context path. Khác với cấu hình bạn nghĩ mình đặt là biết ngay có nguồn nào đang ghi đè, đúng như bài 6.

Started App in 1.138 seconds (process running for 1.36) — hai con số khác nhau: thời gian Spring khởi động, và tổng thời gian tiến trình. Chênh lệch là thời gian JVM khởi động và nạp lớp.

Theo dõi con số thứ nhất theo thời gian. Nó tăng đều nghĩa là bạn đang thêm bean hoặc thêm việc vào @PostConstruct.

Định dạng mỗi dòng

  2026-08-13T04:41:57.766Z  INFO 101 --- [dich-vu-demo] [main] vd.demo.App : Started App in 1.138 seconds
  └─ thời gian            mức  PID     tên ứng dụng   luồng  logger  thông điệp

Tên luồng là cột hữu ích nhất khi gỡ lỗi đồng thời. Thấy [http-nio-8080-exec-3] là biết đang trong một request; thấy [main] là đang khởi động.

Tên ứng dụng đến từ spring.application.name — đặt nó, nhất là khi log của nhiều dịch vụ gom về một chỗ.

Tắt banner

spring:
  main:
    banner-mode: off

Banner ASCII dễ thương nhưng vô dụng trong log sản xuất. Tắt đi.

Bật thông tin thật sự cần

Xem auto-configuration quyết định gì — bài 8:

java -jar app.jar --debug

Xem SQL (bài 27 sẽ nói kỹ):

logging:
  level:
    org.hibernate.SQL: DEBUG
    org.hibernate.orm.jdbc.bind: TRACE

Xem request HTTP nào khớp handler nào:

logging:
  level:
    org.springframework.web: DEBUG

Cả ba đều rất ồn — bật khi điều tra, tắt sau đó.

Cấu hình log cho sản xuất

logging:
  level:
    root: INFO
    vd.demo: DEBUG
  pattern:
    console: "%d{ISO8601} %-5level [%X{maRequest}] %logger{36} - %msg%n"

Ba nguyên tắc, và chúng lặp lại bài 98 sê-ri Java:

Ghi ra stdout, không ghi tệp. Docker và Kubernetes thu log từ đó.

Dùng JSON trong sản xuất. Spring Boot 3.4 có sẵn:

logging:
  structured:
    format:
      console: ecs

Với bản cũ hơn thì dùng logstash-logback-encoder.

Đưa mã tương quan vào mọi dòng qua MDC — %X{maRequest} ở trên. Bài 17 sẽ dựng filter tạo mã đó.

Log ồn che mất cảnh báo thật

Đây là bài học tôi mang từ chính blog này: khi log khởi động bình thường có hàng chục dòng WARN vô hại, bạn ngừng đọc chúng — và bỏ lỡ dòng WARN thật.

Hạ mức những logger ồn cụ thể:

logging:
  level:
    org.apache.catalina: WARN
    org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR

Mục tiêu: log khởi động bình thường không có dòng WARN nào. Đạt được rồi thì mỗi WARN đều đáng đọc.

Hai dòng cần biết khi hỏng

Cổng bị chiếm:

  Web server failed to start. Port 8080 was already in use.

Boot in kèm gợi ý. Đổi cổng bằng --server.port=8081.

Thiếu bean:

  Parameter 0 of constructor in vd.demo.DichVu required a bean of type 'vd.demo.Kho'
  that could not be found.

  Action: Consider defining a bean of type 'vd.demo.Kho' in your configuration.

Thông báo lỗi khởi động của Spring Boot rất tốt — chúng có phần DescriptionAction. Đọc hết trước khi tìm Google.

Nguyên nhân phổ biến nhất của lỗi này: lớp App không ở package gốc, nên @ComponentScan không thấy package chứa bean. Bài 2 đã nói.

Thử ba mươi giây

java -jar app.jar 2>&1 | grep -E "profile|Tomcat started|Started App"

Ba dòng đó cho bạn: profile nào đang chạy, cổng thật, và thời gian khởi động. Đó cũng là ba câu hỏi đầu tiên khi ai đó nói "dịch vụ không lên".

Ngày mai: Actuator — và những endpoint không nên mở ra ngoài.