Logging đúng cách: debug production nhanh hơn

Khi hệ thống lỗi lúc 2 giờ sáng, log là thứ duy nhất kể lại chuyện gì đã xảy ra. Log tệ khiến bạn mù thông tin; log quá nhiều khiến bạn chết chìm trong nhiễu. Bài này chỉ cách log đúng chỗ, đúng mức, đúng định dạng để bạn tìm ra nguyên nhân sự cố nhanh mà không làm phình chi phí hay lộ dữ liệu.

Log để làm gì

Log không phải để thay debugger lúc dev. Mục tiêu chính của log là quan sát hệ thống đang chạy thật, nơi bạn không thể đặt breakpoint. Một dòng log tốt trả lời được: chuyện gì xảy ra, với ai, lúc nào, và đủ ngữ cảnh để tái hiện.

Chọn đúng log level

Dùng level một cách kỷ luật để có thể lọc khi cần. Cách hiểu thực dụng:

Level Khi nào dùng
ERROR Việc thất bại, cần người xem: giao dịch lỗi, exception không xử lý được
WARN Bất thường nhưng hệ thống vẫn chạy: retry, dùng giá trị mặc định
INFO Sự kiện nghiệp vụ đáng chú ý: user đăng ký, đơn hàng tạo
DEBUG Chi tiết kỹ thuật để lần lỗi, thường tắt ở production

Nguyên tắc: nếu mọi thứ đều là ERROR thì không gì là ERROR. Cảnh báo phải hiếm và đáng để ai đó nhìn.

Structured logging: log để máy đọc được

Log dạng câu chữ tự do khó tìm kiếm. Structured logging ghi log dưới dạng cặp khóa-giá trị (thường là JSON), nhờ đó công cụ tập trung log có thể lọc theo user_id, request_id, hay status.

So sánh: "User 123 checkout failed" khó lọc hàng loạt. Trong khi log có trường event=checkout_failed user_id=123 order_id=555 cho phép bạn truy vấn mọi lần checkout lỗi trong ngày chỉ bằng một filter.

Correlation ID: sợi chỉ xuyên suốt

Gắn một ID cho mỗi request và truyền qua mọi service, log ra ID đó ở mọi dòng. Khi debug, bạn lọc theo ID này để thấy toàn bộ hành trình của một request qua nhiều dịch vụ. Đây là công cụ mạnh nhất khi hệ thống có nhiều thành phần.

Ví dụ thực tế

Một dịch vụ thanh toán thỉnh thoảng lỗi. Log ban đầu chỉ ghi "Payment error", vô dụng. Sau khi thêm ngữ cảnh, dòng log thành: level ERROR, event=payment_failed, gateway=stripe, order_id=555, reason=timeout, kèm request_id. Lọc theo reason, đội phát hiện tất cả lỗi đều là timeout vào giờ cao điểm và đều tới cùng một gateway. Nguyên nhân lộ ra ngay: cần tăng timeout và thêm retry. Không có ngữ cảnh đó, việc chẩn đoán có thể kéo dài nhiều ngày.

Lỗi thường gặp và cách sửa

  • Log dữ liệu nhạy cảm. Mật khẩu, token, số thẻ, thông tin cá nhân lọt vào log là rủi ro an ninh và pháp lý. Sửa: che hoặc loại bỏ trước khi ghi, đặt quy tắc rõ ràng cho đội.
  • Log quá nhiều ở production. Chi phí lưu trữ tăng và tín hiệu quan trọng bị chôn. Sửa: đưa chi tiết vào DEBUG, chỉ bật khi cần.
  • Nuốt exception. Bắt lỗi rồi log "error" mà bỏ stack trace. Sửa: luôn log kèm stack trace và ngữ cảnh của lỗi.
  • Log trong vòng lặp nóng. Ghi log mỗi vòng lặp có thể làm chậm hệ thống và ngập log. Sửa: log tổng hợp hoặc lấy mẫu.
  • Thông điệp không có ngữ cảnh. "Không thành công" mà không biết cái gì, của ai. Sửa: luôn kèm định danh và trạng thái liên quan.

Checklist logging

  • Mỗi log có đúng level theo mức độ nghiêm trọng chưa?
  • Log có kèm định danh (user, request, order) để truy vết không?
  • Đã chắc chắn không ghi mật khẩu, token, dữ liệu cá nhân?
  • Lỗi có kèm stack trace và nguyên nhân không?
  • Có correlation ID xuyên suốt các service không?
  • Định dạng có nhất quán để công cụ tìm kiếm đọc được không?

Kết luận

Log tốt là khoản đầu tư trả lãi vào đúng lúc khủng hoảng. Bước tiếp theo cụ thể: rà lại một luồng nghiệp vụ quan trọng nhất của bạn, thêm correlation ID và structured log cho luồng đó, rồi thử tự đặt câu hỏi “nếu luồng này lỗi ở production, log hiện tại có đủ cho tôi tìm ra nguyên nhân không?”.

Câu hỏi thường gặp

Khác nhau giữa logging, monitoring và tracing là gì?

Log ghi lại sự kiện dạng văn bản. Monitoring theo dõi chỉ số tổng hợp như tỉ lệ lỗi, độ trễ. Tracing lần theo đường đi của một request qua nhiều service. Ba thứ bổ trợ nhau, không thay thế nhau.

Nên log ra file hay ra stdout?

Trong môi trường container, thông lệ phổ biến là ghi ra stdout rồi để hạ tầng thu thập và chuyển vào hệ thống log tập trung. Cách này tách ứng dụng khỏi việc quản lý file log.

Có nên log mọi request không?

Một dòng access log cho mỗi request thường hữu ích và chi phí thấp. Nhưng log toàn bộ nội dung request và response thì tốn kém và dễ lộ dữ liệu, chỉ nên bật có chọn lọc khi điều tra.

Làm sao biết mình đang log quá ít hay quá nhiều?

Dấu hiệu quá ít: khi lỗi xảy ra bạn không tái hiện được chuyện gì đã diễn ra. Dấu hiệu quá nhiều: chi phí lưu trữ cao và bạn phải lọc rất nhiều mới thấy thông tin cần. Điều chỉnh dần theo các sự cố thật.

Tham khảo

  • The Twelve-Factor App, mục Logs (12factor.net).
  • Tài liệu về structured logging trong các thư viện log phổ biến của từng ngôn ngữ.

Similar Posts