Python logging模块入门:基本配置、输出到控制台、日志格式设置
日志这东西,说白了就是程序的「黑匣子」。
我刚入行那会儿,排查问题全靠 print(),满屏飘着「这里执行了」「那里报错了」。后来线上出了个诡异 bug,print 语句被同事顺手注释掉了,我愣是找了三个小时才定位到问题。从那以后,我养成了一个习惯——任何项目第一件事,先把日志框架搭好。
今天咱们就从 Python 自带的 logging 模块开始,把最基础的东西吃透。
为什么不用 print?
你想想看,print() 输出到控制台,程序一关就没了。线上环境你总不能一直盯着终端吧?而且 print 没有级别区分,调试信息、警告、错误全混在一起,看着就头疼。
logging 模块就不一样了:
- 可以控制输出到文件、控制台、网络等不同地方
- 有 DEBUG、INFO、WARNING、ERROR、CRITICAL 五个级别
- 可以自定义格式,带上时间、文件名、行号
- 生产环境可以动态调整日志级别,不用改代码
核心观点:print 是调试工具,logging 才是运维工具。别混着用。
最简单的配置:输出到控制台
先来个最基础的例子,看看 logging 长什么样:
import logging
logging.basicConfig(level=logging.INFO)
logging.debug('这条不会显示')
logging.info('程序启动了')
logging.warning('磁盘空间不足')
logging.error('数据库连接失败')
运行一下,控制台会输出:
INFO:root:程序启动了
WARNING:root:磁盘空间不足
ERROR:root:数据库连接失败
看到没?DEBUG 级别的消息被过滤掉了。因为咱们设置了 level=logging.INFO,只有 INFO 及以上的日志才会输出。
小技巧:开发阶段我习惯设成 DEBUG,上线后改成 WARNING 或 ERROR。这样既能看到调试信息,又不会刷爆日志文件。
日志格式设置:让日志更「可读」
刚才的输出太简陋了,连时间都没有。线上排查问题,时间戳是命根子。咱们来格式化一下:
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logging.info('用户登录成功')
输出变成:
2025-01-15 14:30:22 - root - INFO - 用户登录成功
嗯,这下清楚多了。格式字符串里常用的占位符有这些:
| 占位符 | 含义 | 示例 |
|---|---|---|
| %(asctime)s | 时间戳 | 2025-01-15 14:30:22 |
| %(name)s | 日志器名称 | root |
| %(levelname)s | 日志级别 | INFO |
| %(message)s | 日志内容 | 用户登录成功 |
| %(filename)s | 文件名 | app.py |
| %(lineno)d | 行号 | 42 |
注意:datefmt 参数只对 %(asctime)s 生效。如果不指定,默认格式是 2025-01-15 14:30:22,123(带毫秒)。我个人习惯去掉毫秒,看着清爽。
实战:一个完整的入门配置
把上面这些串起来,写一个生产环境可用的基础配置:
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s | %(levelname)-8s | %(filename)s:%(lineno)-4d | %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
logger.debug('开始处理请求')
logger.info('请求参数: %s', {'user_id': 123})
logger.warning('接口响应时间超过阈值: 2.3s')
logger.error('数据库查询失败: timeout')
输出效果:
2025-01-15 14:35:10 | DEBUG | app.py:10 | 开始处理请求
2025-01-15 14:35:10 | INFO | app.py:11 | 请求参数: {'user_id': 123}
2025-01-15 14:35:10 | WARNING | app.py:12 | 接口响应时间超过阈值: 2.3s
2025-01-15 14:35:10 | ERROR | app.py:13 | 数据库查询失败: timeout
这里我用了 %-8s 和 %-4d 做对齐,日志看起来整整齐齐的。线上排查时,一眼就能扫到 ERROR 级别的日志。
避坑指南:我曾经在配置里忘了加 level 参数,结果 DEBUG 日志全打出来了,把磁盘撑爆了。嗯,线上环境一定要记得设日志级别,最好配合日志轮转一起用。
关于日志器名称
刚才代码里用了 getLogger(__name__),这玩意儿有啥用?
说白了,__name__ 就是当前模块的名字。如果你的文件叫 user_service.py,那日志器名字就是 user_service。这样在多模块项目里,一看日志就知道是哪个模块出的问题。
我习惯在项目入口文件用 root 日志器,其他模块各自创建自己的日志器。这样既能统一配置,又能区分来源。
小结
今天咱们干了三件事:
- 用
basicConfig快速配置日志 - 把日志输出到控制台
- 自定义了日志格式,带上时间、级别、位置信息
这些基础操作,够你应付大部分日常开发了。下一节咱们聊聊怎么把日志写到文件里,以及如何处理日志文件轮转——毕竟线上日志可不能一直往一个文件里怼。
课后练习:试着写一个脚本,模拟用户登录流程,分别用 DEBUG、INFO、WARNING、ERROR 记录不同阶段的日志。格式要求:时间精确到秒,显示文件名和行号。