[Java Backend Zero to Hello] BÀI 3.6: LOGGING
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 3: Công Cụ & Build Tools | Bài 34/86
BÀI 3.6: LOGGING
Mục tiêu
- Hiểu tầm quan trọng của logging
- Sử dụng SLF4J với Logback
- Cấu hình logging
- Best practices
1. TẠI SAO CẦN LOGGING?
- Debug ứng dụng
- Theo dõi lỗi trong production
- Phân tích hành vi người dùng
- Audit, compliance
So sánh System.out vs Logger
| System.out | Logger |
|---|---|
| Không có level | Có level (DEBUG, INFO, WARN, ERROR) |
| Không tắt được | Có thể tắt theo level |
| Không ghi file | Ghi file, database, console |
| Không có timestamp | Có timestamp, thread, class |
| Không format | Format được |
2. SLF4J
SLF4J (Simple Logging Facade for Java) là facade cho nhiều logging framework.
2.1 Dependency
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<!-- Logback (implementation) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
2.2 Sử dụng
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
public User findById(Long id) {
log.debug("Finding user by id: {}", id);
log.info("User lookup performed");
log.warn("User not found, returning default");
log.error("Database error", new RuntimeException("Connection failed"));
// ...
}
}
3. LOG LEVEL
| Level | Mô tả | Khi nào dùng |
|---|---|---|
| TRACE | Chi tiết nhất | Debug sâu |
| DEBUG | Thông tin debug | Phát triển |
| INFO | Thông tin chung | Production |
| WARN | Cảnh báo | Có vấn đề nhưng chưa lỗi |
| ERROR | Lỗi | Cần xử lý |
| FATAL | Lỗi nghiêm trọng | Crashed |
Thứ tự
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
4. LOGBACK CONFIGURATION
4.1 File logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Console appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- File appender -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/app.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Rolling file appender -->
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Logger level -->
<logger name="com.example" level="DEBUG"/>
<logger name="org.springframework" level="INFO"/>
<!-- Root logger -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="ROLLING"/>
</root>
</configuration>
4.2 Pattern phổ biến
| Pattern | Mô tả |
|---|---|
%d |
Timestamp |
%thread |
Thread name |
%-5level |
Log level (căn trái 5 ký tự) |
%logger{36} |
Tên class (rút gọn 36 ký tự) |
%msg |
Message |
%n |
New line |
%X{userId} |
MDC value |
%exception |
Stack trace |
5. MDC (Mapped Diagnostic Context)
Thêm context cho log (ví dụ: request ID, user ID).
import org.slf4j.MDC;
MDC.put("requestId", "12345");
MDC.put("userId", "user-001");
log.info("Processing request"); // Sẽ có requestId, userId
MDC.clear();
Pattern: %X{requestId}
6. LOG TRONG SPRING BOOT
Spring Boot mặc định dùng Logback.
6.1 application.yml
logging:
level:
root: INFO
com.example: DEBUG
org.springframework: INFO
file:
name: logs/app.log
pattern:
console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
6.2 Lombok @Slf4j
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserService {
public void createUser(User user) {
log.info("Creating user: {}", user.getName());
}
}
7. BEST PRACTICES
7.1 ✅ NÊN
// Dùng placeholder thay string concatenation
log.debug("User {} created with id {}", name, id);
// Log exception với stack trace
log.error("Failed to process", exception);
// Log có ý nghĩa
log.info("Order {} placed successfully", orderId);
7.2 ❌ KHÔNG NÊN
// String concatenation (chậm)
log.debug("User " + name + " created"); // ❌
// Log thông tin nhạy cảm
log.info("Password: " + password); // ❌
// Log quá nhiều trong vòng lặp
for (int i = 0; i < 1000000; i++) {
log.info("Processing " + i); // ❌
}
7.3 Performance
// Check level trước khi tính toán phức tạp
if (log.isDebugEnabled()) {
log.debug("Complex data: {}", expensiveOperation());
}
8. LOG4J2 (LỰA CHỌN KHÁC)
Dependency
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.22.0</version>
</dependency>
Sử dụng (giống SLF4J)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
9. BÀI TẬP THỰC HÀNH
Bài 1: Cấu hình Logback
Tạo logback.xml với:
- Console + File appender
- Rolling theo ngày
- Level DEBUG cho package của bạn
Bài 2: Logging trong Service
@Service
@Slf4j
public class OrderService {
public Order createOrder(OrderRequest request) {
log.info("Creating order for customer: {}", request.getCustomerId());
try {
Order order = processOrder(request);
log.info("Order {} created successfully", order.getId());
return order;
} catch (Exception e) {
log.error("Failed to create order for customer: {}",
request.getCustomerId(), e);
throw e;
}
}
}
Bài 3: MDC cho request tracking
@Component
public class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String requestId = UUID.randomUUID().toString();
MDC.put("requestId", requestId);
try {
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
10. TÓM TẮT
| Khái niệm | Mô tả |
|---|---|
| SLF4J | Facade cho logging |
| Logback | Implementation phổ biến |
| Log level | TRACE, DEBUG, INFO, WARN, ERROR |
| Appender | Nơi ghi log (console, file) |
| Rolling | Tự động tạo file mới |
| MDC | Context cho log |
| Placeholder | {} thay vì concatenation |
Hoàn thành Phase 3! Tiếp tục với Phase 4: Database & SQL
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 3.5: GRADLE (TÙY CHỌN)
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: PHASE 4: DATABASE & SQL - Tổng Quan & Mục Tiêu
All rights reserved