本文最后更新于 2025-09-10,文章内容可能已经过时。

别再用print调试了!Python Logging模块帮你省50%排错时间

一、先问个扎心的问题:你还在这么做日志吗?

如果你写 Python 时,遇到这些场景会头疼,那这篇文章就是为你写的:

  • 调试时用print("这里到了"),上线前要手动删 / 注释掉,漏一个就尴尬;

  • 线上程序报错,只知道 “有问题”,不知道是哪个模块、什么时间、具体上下文触发的;

  • 想把日志存到文件,又想在控制台看实时输出,结果写了一堆with open(...)代码。

其实 Python 自带的logging模块,早就把这些问题解决了 —— 而且不用装任何第三方库。

二、5 分钟上手:最实用的 3 个基础操作

1. 替代 print:让日志自带 “时间 + 级别”

先抛掉复杂配置,从最简单的开始。用logging打印一条日志,比 print 多带了时间日志级别(比如 INFO、ERROR),排错时一眼就知道什么时候发生了什么:

import logging

\# 第一步:配置基础日志(只需要写一次)

logging.basicConfig(

&#x20;   level=logging.INFO,  # 日志级别:DEBUG < INFO < WARNING < ERROR < CRITICAL

&#x20;   format="%(asctime)s - %(levelname)s - %(message)s"  # 日志格式:时间+级别+内容

)

\# 第二步:用日志替代print

logging.debug("这是调试信息,比如变量值:x=10")  # 不会显示(因为level设为INFO)

logging.info("程序启动成功,开始处理数据")        # 会显示:2024-05-20 14:30:00,123 - INFO - 程序启动成功...

logging.error("读取文件失败!路径:./data.csv")   # 会显示,还能标红(部分终端支持)

👉 关键区别:print是 “无脑输出”,logging能帮你按 “重要程度” 过滤日志 —— 比如上线时把level改成WARNING,就只看警告和错误,不看琐碎的调试信息。

2. 把日志存到文件:再也不怕程序崩了没记录

如果程序在服务器上跑,控制台日志关了就没了。用filename参数让日志自动存到文件,还能设置文件大小 / 备份(避免日志文件占满硬盘):

logging.basicConfig(

&#x20;   level=logging.INFO,

&#x20;   format="%(asctime)s - %(module)s - %(levelname)s - %(message)s",  # 多加个“模块名”

&#x20;   filename="app.log",  # 日志存到这个文件

&#x20;   filemode="a",  # 追加模式(避免覆盖旧日志)

&#x20;   encoding="utf-8"  # 解决中文乱码问题

)

\# 测试:这行日志会同时显示在控制台+写入app.log

logging.error("用户登录失败:用户名不存在")

打开app.log文件,会看到这样的内容,比纯控制台输出好追溯多了:

2024-05-20 14:35:00,456 - login - ERROR - 用户登录失败:用户名不存在

3. 多模块协作:日志能分清 “谁在报错”

如果你写的项目有多个文件(比如main.py调用utils.py),logging能自动标明日志来自哪个模块,不用你手动加注释:

\# utils.py

import logging

def read\_file(path):

&#x20;   try:

&#x20;       with open(path) as f:

&#x20;           return f.read()

&#x20;   except Exception as e:

&#x20;       logging.error(f"读取文件出错:{e}", exc\_info=True)  # exc\_info=True:显示完整报错栈

\# main.py

import logging

import utils

logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(module)s - %(message)s")

utils.read\_file("./nonexistent.txt")  # 调用不存在的文件,触发错误

日志会清晰显示 “错误来自 utils 模块”,连报错栈都有,定位问题超快:

2024-05-20 14:40:00,789 - utils - 读取文件出错:\[Errno 2] No such file or directory: './nonexistent.txt'

Traceback (most recent call last):

&#x20; File "utils.py", line 4, in read\_file

&#x20;   with open(path) as f:

FileNotFoundError: \[Errno 2] No such file or directory: './nonexistent.txt'

三、坦白说:Logging 模块的 3 个 “坑”,新手很容易踩

虽然logging好用,但它不是完美的 —— 这些缺点我踩过,提前告诉你省时间:

1. 默认配置太 “简陋”,自定义要学一堆概念

basicConfig只能应付简单场景,想做 “同时输出到控制台和文件”“按日期分割日志(比如每天一个文件)”,就得学LoggerHandlerFormatter这些概念,新手容易绕晕:

  • 比如你想 “控制台显示 INFO 以上,文件存 DEBUG 以上”,得手动创建两个Handler,再绑定到Logger上,代码比basicConfig复杂 3 倍。

2. 多线程 / 多进程下可能丢日志

如果你的程序用了多线程(比如threading)或多进程(比如multiprocessing),直接用logging可能会丢日志 —— 比如两个线程同时写日志,会出现日志内容重叠、甚至部分日志没写进去的情况。

👉 解决办法:需要手动加锁(比如用logging.handlers.QueueHandler),但又要多写一堆代码,不够 “开箱即用”。

3. 配置文件写起来麻烦

如果项目大了,不想把日志配置写在代码里(想单独放个log.conf文件),logging支持的配置格式(比如 INI、JSON)都不太友好:

  • INI 格式要记一堆[loggers] [handlers]节点,写错一个逗号就生效不了;

  • JSON 格式虽然熟悉,但嵌套层级多,看着就累。

四、进阶技巧:让 Logging 用起来更爽

1. 用dictConfig简化复杂配置

不想记Handler的创建步骤?用dictConfig把配置写成字典,结构更清晰,复制粘贴就能用(比如 “控制台 + 文件双输出”):

import logging.config

log\_config = {

&#x20;   "version": 1,

&#x20;   "disable\_existing\_loggers": False,

&#x20;   "formatters": {  # 定义日志格式

&#x20;       "standard": {"format": "%(asctime)s - %(module)s - %(levelname)s - %(message)s"}

&#x20;   },

&#x20;   "handlers": {  # 定义两个Handler:控制台+文件

&#x20;       "console": {

&#x20;           "class": "logging.StreamHandler",

&#x20;           "level": "INFO",

&#x20;           "formatter": "standard"

&#x20;       },

&#x20;       "file": {

&#x20;           "class": "logging.FileHandler",

&#x20;           "level": "DEBUG",

&#x20;           "formatter": "standard",

&#x20;           "filename": "app.log",

&#x20;           "encoding": "utf-8"

&#x20;       }

&#x20;   },

&#x20;   "root": {  # 根Logger,把两个Handler加进来

&#x20;       "level": "DEBUG",

&#x20;       "handlers": \["console", "file"]

&#x20;   }

}

\# 加载配置

logging.config.dictConfig(log\_config)

\# 测试:会同时输出到控制台和文件

logging.debug("调试信息:用户ID=123")

logging.error("数据库连接超时")

2. 嫌麻烦?试试第三方替代:Loguru

如果觉得logging配置太繁琐,推荐用loguru(需要pip install loguru)—— 它把logging的复杂逻辑封装了,一行代码就能实现 “控制台 + 文件 + 按日期分割”:

from loguru import logger

\# 一行配置:输出到控制台+每天一个日志文件(保留30天)

logger.add("app\_{time:YYYY-MM-DD}.log", rotation="1 day", retention=30, encoding="utf-8")

logger.info("程序启动")

logger.error("数据处理失败")

👉 缺点:如果项目已经用了logging,替换起来要改不少代码,适合新项目起步用。

最后:总结一下什么时候用 Logging

  • 写小脚本调试:用print没问题(快);

  • 项目超过 2 个文件、要上线、需要追溯错误:一定要用logging

  • 觉得logging配置麻烦、新项目:试试loguru

你之前用print踩过什么坑?或者logging有什么没搞懂的地方?评论区聊聊~

(注:文档部分内容可能由 AI 生成)