大家好,今天咱们来聊一个能直接让你少掉几根头发的神器------Python logging 库。
你是不是经常这样: 代码写到一半,逻辑有点乱,于是手一抖,敲下了熟悉的 print("debug...")
。结果越写越乱,满屏幕的输出让人眼睛花;调试完还得一个个删掉,不删吧心里不踏实,删吧又怕删漏。最后,整个人被"print调试"折磨到怀疑人生。
别问我为什么懂,我也曾是 print()
调试的受害者。
后来,我遇到了 logging 库,那一刻我才发现:原来调试也能这么优雅!
今天,我就带你彻底搞懂 logging 库------从入门到进阶,从基础配置到自定义类。保证你看完之后,代码调试思路清爽到飞起,再也不用和 print()
苦苦纠缠。
1. 为什么 print() 不够用?
说实话,print()
并不是完全没用,它就像炒菜时的"生抽",偶尔点缀一下能提味。
但是!如果你把整道菜全靠"生抽"撑着,那只会变成一锅咸汤。
举个例子: 你写了 200 行代码,里面夹杂了 30 个 print()
,运行的时候屏幕刷得比股市行情还快。调试完你还得手动删除,万一漏掉几个,可能上线之后还傻乎乎地往控制台狂输出。
更要命的是,print()
输出的内容一锅乱炖,没有级别、没有格式,查问题的时候就像在大海捞针。
而 logging 库 就不一样了,它能帮你:
- 分级别输出日志:调试信息、警告、错误一清二楚。
- 定义输出格式:带时间、带模块名,看着就舒服。
- 保存到文件:以后回溯问题,不用苦逼地翻控制台历史。
- 多路输出:想控制台看,还是文件看,随便你。
一句话总结:logging 是调试的艺术,print 只是临时凑合。
2. logging 的"Hello World"
先别怕复杂,我们从最简单的例子开始。
python
import logging
# 设置基本配置,日志级别为DEBUG
logging.basicConfig(level=logging.DEBUG)
# 输出一条INFO级别的日志
logging.info('这是一条信息日志')
# 输出一条DEBUG级别的日志
logging.debug('这是一条调试日志')
# 输出一条WARNING级别的日志
logging.warning('这是一条警告日志')
# 输出一条ERROR级别的日志
logging.error('这是一条错误日志')
# 输出一条CRITICAL级别的日志
logging.critical('这是一条严重错误日志')
运行一下,输出类似这样:
less
INFO:root:这是一条信息日志
DEBUG:root:这是一条调试日志
WARNING:root:这是一条警告日志
ERROR:root:这是一条错误日志
CRITICAL:root:这是一条严重错误日志
看到没?光是比 print()
,它就已经高级太多了。
这里有个重点: 日志级别是有优先级的,从低到高分别是: DEBUG < INFO < WARNING < ERROR < CRITICAL。
比如你把日志级别设置成 ERROR
,那么 DEBUG、INFO、WARNING 就不会输出,只有 ERROR 和 CRITICAL 才会被打印出来。是不是很灵活?
3. 日志级别背后的"小心机"
有同学可能会问:这些日志级别到底该怎么用?
我来给你套个生活里的比喻:
- DEBUG:就像你在厨房里自言自语,"这火是不是小了点?再放点盐试试。"------全是内部小碎碎念。
- INFO:类似你对朋友说:"这道菜大体还行,能吃。"------正常的状态汇报。
- WARNING:就像你妈在旁边提醒你:"油烟太大,小心呛着。"------不致命,但要注意。
- ERROR:相当于你炒菜时锅糊了,菜还能救,但味道打折。
- CRITICAL:锅直接着火了,别炒了,赶紧灭火吧!
是不是一下就记住了?
4. 给日志加点"排面":自定义格式
默认日志的样子有点单调,光是 INFO:root:xxx
难免乏味。
logging 支持自定义格式,比如加上时间、日志级别、消息内容,看着更清晰:
ini
import logging
# 设置日志格式
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logging.debug('这是一条调试日志')
logging.info('这是一条信息日志')
输出效果:
yaml
2025-01-12 10:23:56,123 - root - DEBUG - 这是一条调试日志
2025-01-12 10:23:56,124 - root - INFO - 这是一条信息日志
是不是更有"专业感"了? 在公司项目里,这种带时间戳的日志特别重要,出了问题直接一眼能定位是哪一刻发生的。
5. 日志写入文件:让 Bug 留下"案底"
现实场景里,光看控制台不够。你下班了,服务器还在跑,出了问题你也得有证据。
这时候,就要把日志写到文件里:
ini
import logging
# 将日志记录到文件
logging.basicConfig(level=logging.DEBUG,
filename='app.log',
format='%(asctime)s - %(levelname)s - %(message)s')
logging.info('这条日志会被写入到文件中')
运行完后,你会发现当前目录下多了一个 app.log
文件,里面乖乖地躺着日志。
这就是"案底"。哪怕你过几天才回头看,也能找到问题发生的全过程。
6. 高级玩法:多处理器 + 格式化
如果你想要"既输出到控制台,又保存到文件",那就得用到 logger、handler、formatter 这套组合拳了。
看代码:
ini
import logging
# 创建logger对象
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
# 创建一个控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 创建一个文件处理器
file_handler = logging.FileHandler('my_log.log')
file_handler.setLevel(logging.DEBUG)
# 创建formatter并将其设置到处理器
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 将处理器添加到logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 测试日志输出
logger.debug('调试信息')
logger.info('普通信息')
logger.warning('警告信息')
这样,你就能一边在控制台看实时日志,一边在文件里存历史记录,互不耽误。
这可是大型项目的标配操作。
7. 封装一个属于自己的 Log 类
到这里,你可能觉得配置 handler、formatter 有点繁琐。
没关系,我们可以自己封装一个 Log
类,把这些细节都打包好,直接复用。
python
import logging
class Log:
def __init__(self, name="my_logger", level=logging.DEBUG, log_file="app.log"):
"""
初始化日志器
:param name: 日志器名称
:param level: 日志级别
:param log_file: 日志输出文件
"""
# 创建logger对象
self.logger = logging.getLogger(name)
self.logger.setLevel(level)
# 创建一个控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 创建一个文件处理器
file_handler = logging.FileHandler(log_file)
file_handler.setLevel(level)
# 创建formatter并将其设置到处理器
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 将处理器添加到logger
self.logger.addHandler(console_handler)
self.logger.addHandler(file_handler)
def debug(self, message):
"""记录DEBUG级别日志"""
self.logger.debug(message)
def info(self, message):
"""记录INFO级别日志"""
self.logger.info(message)
def warning(self, message):
"""记录WARNING级别日志"""
self.logger.warning(message)
def error(self, message):
"""记录ERROR级别日志"""
self.logger.error(message)
def critical(self, message):
"""记录CRITICAL级别日志"""
self.logger.critical(message)
# 测试自定义Log类
if __name__ == "__main__":
log = Log(name="custom_logger", level=logging.DEBUG, log_file="custom_log.log")
log.debug("这是一条调试日志")
log.info("这是一条信息日志")
log.warning("这是一条警告日志")
log.error("这是一条错误日志")
log.critical("这是一条严重错误日志")
这样一来,你以后想打日志,就只需要:
lua
log.info("程序启动成功")
log.error("数据库连接失败")
是不是干净利落?
8. logging 的实战价值
说到这里,有人可能会问: "我只是写个小脚本,用 print 也没啥啊?"
没错,小脚本用 print 确实够了。
但是,一旦你进入 团队协作、线上项目、数据分析平台 这些场景,你就会发现:
- 领导要看系统是否正常运行,得靠 INFO 日志。
- 出问题时,开发要查 DEBUG 日志找原因。
- 安全部门要追踪系统异常,得用 ERROR 和 CRITICAL 日志。
换句话说,logging 是 专业开发者的基本功,它不仅仅是"调试工具",更是"系统的眼睛"。

9. 小结:从 print 到 logging 的升级
今天我们学了:
- 为什么 print 不够用,logging 更优雅。
- logging 的基本用法和日志级别。
- 如何自定义日志格式,让输出更清晰。
- 如何把日志保存到文件,留"案底"。
- 用 handler + formatter 搭建复杂日志系统。
- 封装一个 Log 类,优雅复用。
如果说 print()
是自行车,那么 logging 就是汽车。 一开始可能需要学点"驾驶技巧",但一旦上手,速度、稳定性、安全性都不是一个量级。
所以,下次你再写 Python 代码的时候,别再傻乎乎用 print 满屏乱飞了。试试 logging,让调试优雅起来!
最后抛个问题: 👉 你现在项目里还在用 print 调试吗?还是已经切换到 logging 了?
欢迎在评论区聊聊,我想听听你的故事。