print 的问题

print("用户登录:", user.name)

写脚本可以,写应用就不行:

  • 开发期想看,生产期不想看 → 没法关
  • 错误和正常信息混在一起 → 没法过滤
  • 没时间戳 / 模块名 / 行号 → 排查难
  • 不能写到文件 → 重启就丢

logging 模块解决全部。

最快上手

import logging
logging.basicConfig(level=logging.INFO)

logging.info("应用启动")
logging.warning("配置缺失,使用默认")
logging.error("数据库连接失败")

输出:

INFO:root:应用启动
WARNING:root:配置缺失,使用默认
ERROR:root:数据库连接失败

五个级别

级别 何时用
DEBUG 开发期排查细节
INFO 关键事件(启动 / 用户登录 / 任务完成)
WARNING 异常但能继续(配置缺失、降级)
ERROR 单次失败(API 调用失败、文件读不到)
CRITICAL 系统崩了(无法继续运行)

level=INFO 表示 INFO 及以上都会打印,DEBUG 不打。

用模块级 logger(推荐姿势)

import logging

logger = logging.getLogger(__name__)        # 用模块名做 logger 名

def do_work():
    logger.info("开始工作")
    try:
        ...
    except Exception:
        logger.exception("工作失败")          # 自动附 traceback

永远 getLogger(__name__),别直接用 logging.info()——前者能精确控制每个模块的级别。

漂亮的输出格式

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)-7s | %(name)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)

输出:

2026-05-09 14:23:01 | INFO    | myapp.web | 用户登录: WadeLy

日志写到文件 + 同时显示在终端

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    handlers=[
        logging.FileHandler("app.log"),
        logging.StreamHandler(),       # 终端
    ],
)

日志轮转:避免文件无限大

from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler(
    "app.log", maxBytes=5_000_000, backupCount=5
)
# 单文件最大 5MB,保留 5 份历史
logging.basicConfig(handlers=[handler], level=logging.INFO)

logger.exception:错误自动带 traceback

try:
    risky()
except Exception:
    logger.exception("risky 失败")
# 输出会自带 traceback,不用手动拼

异常打印的"懒求值"

# 坏:永远计算字符串
logger.debug(f"data = {expensive_func()}")

# 好:只在 DEBUG 时计算
logger.debug("data = %s", expensive_func())

logging 内部判断级别后才格式化字符串——传 %s + 参数比 f-string 高效。

structlog:结构化日志(生产推荐)

pip install structlog
import structlog
log = structlog.get_logger()
log.info("user_login", user_id=42, ip="1.2.3.4")
# 2026-05-09 14:23 [info] user_login user_id=42 ip=1.2.3.4

字段化输出,配合 ELK / Loki 等日志系统超好用。

一个项目的标准 logging 入口

# logging_config.py
import logging
from logging.handlers import RotatingFileHandler

def setup():
    fmt = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
    logging.basicConfig(
        level=logging.INFO,
        format=fmt,
        handlers=[
            RotatingFileHandler("app.log", maxBytes=10_000_000, backupCount=5),
            logging.StreamHandler(),
        ],
    )

# main.py
from logging_config import setup
setup()

下一篇讲测试 pytest