同事小马最近接了个数据处理的需求,写了个脚本,跑得挺顺。上线第一天,线上报了个错,他赶紧加了一堆 print 看问题在哪。结果第二天上线,日志文件里全是这种输出,真正出错的那行反而被淹没了。
更要命的是,他想关掉这些调试信息,发现得一个一个手动删。
这就是 print 调试的终极问题:调试信息和业务日志混在一起,想关关不掉,想找找不到。
1. logging 模块:Python 自带的日志系统
logging 模块是 Python 标准库自带的,零依赖,不用装。
它解决的核心问题是:让程序的输出分级别、分去向、可控制。
几个关键概念:
Logger:日志的入口,你调 logging.info() 实际上是在调 logger 的方法
Handler:日志往哪送,控制台、文件、网络都行
Formatter:日志长什么样,时间、级别、模块名都可以自定义
Level:日志的紧急程度,DEBUG < INFO < WARNING < ERROR < CRITICAL
跟 print 比,logging 的区别在哪里?
| 维度 | print | logging |
|---|
| 级别区分 | 没有,全混在一起 | 5 级,按紧急程度过滤 |
| 输出去向 | 只能打控制台 | 控制台、文件、网络、邮件都行 |
| 运行时控制 | 要改代码删 print | 改配置就行,不碰业务代码 |
| 格式化 | 自己拼字符串 | 内置模板,时间/线程/模块名自动带 |
2. 从 print 到 logging 的三步迁移
第一步:导包与基础设置
import logginglogging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')logging.info('程序启动')logging.warning('配置文件不存在,使用默认值')logging.error('数据库连接失败')
输出:
2026-08-19 10:30:01 [INFO] 程序启动2026-08-19 10:30:01 [WARNING] 配置文件不存在,使用默认值2026-08-19 10:30:01 [ERROR] 数据库连接失败
第二步:输出到文件
import logginglogging.basicConfig( level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s', handlers=[ logging.FileHandler('app.log', encoding='utf-8'), logging.StreamHandler() ])
第三步:按模块分 logger(生产推荐)
import logginglogger = logging.getLogger(__name__)def process_data(data): logger.info('收到 %d 条数据', len(data)) try: result = transform(data) logger.info('处理完成,输出 %d 条', len(result)) return result except Exception as e: logger.error('处理失败: %s', e, exc_info=True) raise
exc_info=True 会把完整的错误堆栈打出来,比 print 的 print(e) 强太多了。
3. logging 的设计思想
logging 的核心设计思路是关注点分离:
业务代码只管说发生了什么,不管输出到哪
配置层决定日志去控制台还是文件、输出什么格式
运行时通过调整 level 过滤不需要的信息
这意味着:开发环境设 DEBUG 看详细日志,生产环境切 INFO 只看关键信息,业务代码一行不用改。
还有一个容易被忽略的设计:logger 是层级的。
logging.getLogger('app.db') 是 logging.getLogger('app') 的子 logger。
你可以给 app 设一个级别,单独给 app.db 设另一个级别,精细控制每个模块的日志量。
4. 常见问题
basicConfig 调了两次不生效?
是的,basicConfig 只在第一次调用时生效。第二次调用会被忽略。所以一般在程序入口调一次就够了,别到处写。
logging 和 print 混着用会乱吗?
会。
print 输出没有时间戳和级别,跟 logging 的输出混在一起很难看。要么全用 logging,要么至少在生产代码里把 print 换掉。
多线程环境下 logging 安全吗?
安全。
logging 内部做了锁,多线程同时写日志不会交错。print 在多线程下反而可能输出交错。
把 print 换成 logging,是每个Python开发者从脚本走向工程的第一步。配置三行代码,换来的是可控制、可追溯、可搜索的日志体系。
欢迎大家评论区留言讨论~
我是鲁叶的Python,10年互联网古法程序员。
Python/ML/DL/大模型都折腾过,坑也踩了不少。
关注我,持续输出实用干货。