print() đủ dùng khi đang thử nghiệm, nhưng khi chương trình chạy thật trên server bạn cần biết chuyện gì đã xảy ra lúc 3 giờ sáng. Đó là việc của module logging.
Năm mức log
import logging
logging.basicConfig(level=logging.INFO)
logging.debug("Chi tiết dành cho lập trình viên")
logging.info("Sự kiện bình thường: đã xử lý 100 bản ghi")
logging.warning("Bất thường nhưng chưa chết: API chậm")
logging.error("Có lỗi: không kết nối được database")
logging.critical("Nghiêm trọng: hết dung lượng đĩa")
Đặt level=logging.INFO nghĩa là bỏ qua DEBUG, chỉ ghi từ INFO trở lên. Khi cần soi lỗi, hạ xuống DEBUG mà không phải sửa một dòng code nào khác.
Ghi ra file kèm thời gian
logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
encoding="utf-8",
)
Mỗi module một logger riêng
# Trong từng file .py
logger = logging.getLogger(__name__)
def xu_ly(don_hang):
logger.info("Bắt đầu xử lý đơn %s", don_hang.ma)
Dùng %s thay vì f-string: chuỗi chỉ được ghép khi log thực sự được ghi, tiết kiệm chút hiệu năng ở mức DEBUG.
Ghi lại toàn bộ lỗi
try:
ket_qua = 10 / 0
except ZeroDivisionError:
logger.exception("Lỗi khi tính toán") # tự kèm traceback đầy đủ
Xoay vòng file để không đầy ổ đĩa
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
"app.log", maxBytes=5_000_000, backupCount=5, encoding="utf-8"
)
handler.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(message)s"))
logging.getLogger().addHandler(handler)
File log vượt 5 MB sẽ được đổi tên thành app.log.1 và tạo file mới, giữ tối đa 5 file cũ.
Ba nguyên tắc nên nhớ
- Không bao giờ ghi mật khẩu, token hay số thẻ vào log.
- Log phải trả lời được câu hỏi “chuyện gì, với dữ liệu nào” — kèm mã đơn, ID người dùng.
- Chỉ gọi
basicConfigmột lần, ở điểm khởi động ứng dụng.
Chuyển từ print sang logging tốn vài phút, nhưng sẽ tiết kiệm cho bạn nhiều giờ mò lỗi về sau.
