99 Ngày Spring — Ngày 92: Structured Logging
Trên máy dev, bạn đọc log bằng mắt. Ở production, mười instance sinh hàng triệu dòng mỗi giờ và thứ đọc log là máy. Structured logging nghĩa là mỗi dòng log là một bản ghi có trường rõ ràng, thường là JSON, để hệ thống tập trung log lọc và tổng hợp được mà không cần regex.

1. Bật log JSON
Từ Spring Boot 3.4, structured logging là tính năng có sẵn: một thuộc tính chuyển console sang JSON theo định dạng ECS, Logstash hoặc GELF. Với phiên bản cũ hơn, dùng logstash-logback-encoder cho cùng kết quả. Ứng dụng chỉ ghi ra stdout; việc thu gom và chuyển tiếp là của nền tảng. Giữ định dạng dễ đọc cho máy dev bằng profile.
# application-prod.properties
logging.structured.format.console=ecs
logging.structured.ecs.service.name=orders
logging.structured.ecs.service.environment=production2. Key-value thay cho ghép chuỗi
Thông điệp nên là một câu cố định, còn dữ liệu thay đổi nằm trong trường riêng. Nhờ đó bạn đếm được số lần một sự kiện xảy ra và lọc theo orderId mà không phải tách chuỗi. API fluent của SLF4J 2 thêm key-value vào bản ghi; với placeholder {} thì thông điệp vẫn được tham số hóa và không tốn công ghép chuỗi khi mức log bị tắt.
log.atInfo()
.addKeyValue("orderId", order.id())
.addKeyValue("amount", order.total())
.log("Order paid");
// {"@timestamp":"...","log.level":"INFO","message":"Order paid",
// "orderId":"42","amount":1350000,"trace.id":"8f3c..."}3. MDC và correlation id
MDC là một map gắn với luồng đang chạy; mọi dòng log trong luồng đó tự mang các giá trị này. Khi có Micrometer Tracing, traceId và spanId được đưa vào MDC tự động, nên chỉ cần tìm một traceId là thấy log của cùng request trên mọi service. Với dữ liệu nghiệp vụ tự thêm, luôn xóa trong finally vì luồng trong pool được tái sử dụng và giá trị cũ sẽ dính sang request sau.
MDC.put("tenant", tenantId);
try {
orderService.process(command); // every log line carries "tenant"
} finally {
MDC.remove("tenant");
}4. Tập trung log và giữ log sạch
Container ghi ra stdout, một agent thu gom và gửi tới hệ thống như Loki, Elasticsearch hoặc dịch vụ của cloud. Ở đó log được tìm theo trường và nối với trace, metric. Chi phí lưu trữ tăng theo số dòng, nên mức log ở production thường là INFO và phải đổi được lúc chạy qua Actuator khi cần điều tra.
Không log mật khẩu, token, số thẻ hay dữ liệu cá nhân; che ngay tại nguồn.
ERROR là thứ cần người xử lý; lỗi do người dùng nhập sai không phải ERROR.
Log exception một lần, ở nơi xử lý nó, kèm stack trace.
Tên trường thống nhất giữa các service: orderId ở đâu cũng là orderId.
Log có cấu trúc trả lời chuyện gì đã xảy ra với một request. Ngày 93 trả lời câu hỏi còn lại: hệ thống đang khỏe hay yếu, bằng metric với Prometheus và Grafana.
Tài liệu đối chiếu
https://docs.spring.io/spring-boot/reference/features/logging.html
https://www.slf4j.org/manual.html
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


