Python logging 模块

Levels, handlers, formatters, and the difference between basicConfig and a real setup.

Intermediate
Key PointsLibrary code should only call `logger.info(...)` and never configure logging — configuration belongs to the application entry point.

Levels

Levels go DEBUG < INFO < WARNING < ERROR < CRITICAL. Setting INFO drops DEBUG records.

Python
import logging

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")
log = logging.getLogger("app")

log.debug("不可见")
log.info("启动完成")
log.warning("磁盘 85%")
log.error("连接失败")
Output
INFO app 启动完成
WARNING app 磁盘 85%
ERROR app 连接失败

A Real Setup

basicConfig is for scripts. Real services build handlers: console plus a rotating file, with one format.

Python
import logging
from logging.handlers import RotatingFileHandler

fmt = logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s")

console = logging.StreamHandler()
console.setFormatter(fmt)

file_h = RotatingFileHandler("app.log", maxBytes=10 * 1024 * 1024, backupCount=5, encoding="utf-8")
file_h.setFormatter(fmt)

logger = logging.getLogger("app")
logger.setLevel(logging.INFO)
logger.addHandler(console)
logger.addHandler(file_h)

logger.info("service started")
Output
2026-10-31 10:40:12,331 INFO app service started

Rules

RuleWhy
Use lazy formatting: log.info("%s", x)Avoids building strings when the level is off
One logger per module: getLogger(__name__)Filtering by module becomes possible
Never log secrets or full card numbersLogs get shipped and stored
Log exceptions with exc_info=TrueKeeps the traceback
Python
try:
    1 / 0
except ZeroDivisionError:
    logger.exception("计算失败")     # 等价于 error(..., exc_info=True)
print has no level, no timestamp and cannot be turned off. Fine while debugging, logging in production.

Friends & Partners