Mở đầu
Tập này thiết lập logging tập trung và bắt lỗi bằng Sentry cho ứng dụng quản lý chi tiêu, để mọi lỗi trên production đều để lại dấu vết đầy đủ thay vì chỉ hiện một trang 500 chung chung. Nối tiếp tập 6 về migrations an toàn, đây là bước giúp bạn phát hiện lỗi sau mỗi lần deploy sớm nhất, trước khi người dùng kịp báo cáo. Kết quả cuối tập: log có cấu trúc theo từng request, và lỗi tự động gửi về Sentry kèm phiên bản deploy gây ra lỗi.
1. Vì sao print và log mặc định không đủ
Django mặc định ghi log ra console, và khi ứng dụng chạy nhiều worker Gunicorn như ở tập 3, log rải rác theo từng tiến trình, không có mã định danh để lần theo một request. Lệnh print còn tệ hơn: không mức độ, không thời gian chuẩn. Production cần ba thứ: định dạng thống nhất, một nơi tập hợp, và cảnh báo khi lỗi mới xuất hiện.
2. Cấu hình logging có cấu trúc
Trong settings production đã tách riêng từ tập 2, khai báo LOGGING bằng dictConfig: formatter ghi thời gian, mức độ, tên logger và mã request; handler console để hệ thống thu thập log đọc được. Bật INFO cho logger ứng dụng và WARNING cho thư viện ngoài. Quan trọng nhất: không ghi mật khẩu hay token vào log, và dùng filter che trường nhạy cảm.
LOGGING = { "version": 1, "disable_existing_loggers": False, "formatters": { "structured": { "format": "{asctime} {levelname} {name} request={request_id} {message}", "style": "{", }, }, "handlers": { "console": {"class": "logging.StreamHandler", "formatter": "structured"}, }, "loggers": { "expenses": {"handlers": ["console"], "level": "INFO", "propagate": False}, "django": {"handlers": ["console"], "level": "WARNING", "propagate": False}, },}
3. Gắn Sentry để bắt lỗi tự động
Cài sentry-sdk rồi khởi tạo trong settings production, với DSN lấy từ biến môi trường chứ không ghi cứng vào code. Đặt traces_sample_rate ở mức 0,1 để chỉ lấy mẫu một phần mười request cho việc đo hiệu năng, tiết kiệm quota mà vẫn đủ phát hiện endpoint chậm. Tắt send_default_pii để Sentry không thu thập địa chỉ IP mặc định, và gắn release theo từng bản deploy để biết lỗi thuộc phiên bản nào. Sentry tự bắt exception chưa xử lý; với lỗi đã bắt nhưng nghiêm trọng, hãy gọi capture_exception tường minh.
import sentry_sdksentry_sdk.init( dsn=env("SENTRY_DSN"), traces_sample_rate=0.1, send_default_pii=False, release=env("APP_RELEASE", default="unknown"),)
4. Quy trình xử lý lỗi mỗi ngày
Mỗi sáng, xem các issue mới trên Sentry và phân loại ngay: lỗi mới sau một lần deploy thì ưu tiên rollback hoặc hotfix, lỗi cũ lặp lại thì tạo ticket sửa trong tuần. Đặt cảnh báo cho lỗi hoàn toàn mới và tần suất tăng đột biến. Chỉ đóng issue sau khi bản sửa đã deploy và 24 giờ không tái phát.
Áp dụng vào dự án của bạn
Bắt đầu với ứng dụng quản lý chi tiêu: bật Sentry ở staging trước một tuần, tạo một lỗi giả lập để kiểm tra toàn bộ luồng đến khi cảnh báo tới tay bạn. Giai đoạn đầu chỉ bật cảnh báo cho lỗi mới, tránh ngập thông báo từ lỗi cũ. Sau đó áp dụng đúng cấu hình đó sang production.
Bài viết liên quan
- Django vận hành production #6: Migrations an toàn trên production
- Django vận hành production #5: Static và media — WhiteNoise, S3/MinIO và cache headers
- Django vận hành production #4: PostgreSQL trên production — PgBouncer và backup cơ bản
Câu hỏi thường gặp
Sentry có thay thế hoàn toàn logging không?
Không. Sentry giỏi bắt và cảnh báo lỗi, còn log ghi lại toàn bộ hành trình của request. Bạn cần cả hai: log để điều tra, Sentry để không bỏ sót lỗi.
traces_sample_rate nên đặt bao nhiêu?
Với ứng dụng vừa và nhỏ, 0,1 là điểm khởi đầu hợp lý. Nếu quota eo hẹp, hãy hạ xuống 0,05; nếu đang điều tra một endpoint chậm cụ thể, có thể tạm tăng lên 1,0 trong thời gian ngắn.
Lỡ log chứa dữ liệu nhạy cảm thì xử lý thế nào?
Dừng ghi log đó ngay, thêm filter che trường nhạy cảm, rồi xoay lại các secret đã lộ và xóa log cũ khỏi nơi lưu trữ. Đừng chỉ sửa code mà để nguyên log cũ còn chứa secret.
Nguồn tham khảo
- Tài liệu Django về logging và tài liệu Sentry cho Django SDK.
