3. 配置日志记录器:三种套路,你用哪种?
配置日志,说白了就是告诉 Python:「日志该怎么写、写到哪里、写多详细」。我见过不少新手,直接 logging.basicConfig 一把梭,跑起来没问题,一到生产就抓瞎。今天我把三个主流配置方式捋一遍,你根据自己的场景选就行。
3.1 basicConfig —— 最省事的入门配置
如果你只是写个脚本、做个原型,basicConfig 是你的好朋友。它一句话就能搞定日志的基本框架。
我习惯在 main 函数开头写,因为 basicConfig 默认只生效一次,之后再调用就没效果了。第一次的配置会覆盖后面的。
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='app.log',
filemode='a'
)
logging.info("程序启动")
这里有个坑,你想想看——filename 指定了以后,日志就只往文件写,控制台不输出了。我曾经因为这个问题,排查了半天,以为是日志没写对……后来才发现是控制台被关了。
注意: basicConfig 不支持同时输出到文件和控制台,也不支持滚动日志。生产环境别只用这个。
3.2 字典配置 —— 生产环境的首选
说实话,这才是真正能用的配置方式。用字典配置,你可以精准控制 logger、handler、formatter 的每个细节。
import logging.config
config_dict = {
'version': 1,
'formatters': {
'default': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
},
'detailed': {
'format': '%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s'
}
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'level': 'DEBUG',
'formatter': 'default',
'stream': 'ext://sys.stdout'
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'level': 'INFO',
'formatter': 'detailed',
'filename': 'app.log',
'maxBytes': 10485760,
'backupCount': 5
}
},
'loggers': {
'mymodule': {
'level': 'DEBUG',
'handlers': ['console', 'file'],
'propagate': False
}
},
'root': {
'level': 'WARNING',
'handlers': ['console']
}
}
logging.config.dictConfig(config_dict)
logging.getLogger('mymodule').info("字典配置生效")
你看,handler 可以是控制台,也可以是滚动文件,还可以自己加网络 handler。formatter 也可以按模块区分。我个人习惯把 Root logger 只开 WARNING,各个业务模块独立的 logger 再开 INFO 或 DEBUG,这样不会被噪音淹没。
3.3 文件配置 —— 团队协作的利器
当项目大了,配置写成 Python 字典放代码里不方便修改。这时候用 fileConfig 就很香——把配置塞进 .ini 或 .conf 文件,运维同学直接改文件,不用动代码。
配置文件示例:logging.ini
[loggers]
keys=root,mymodule
[handlers]
keys=consoleHandler,fileHandler
[formatters]
keys=defaultFormatter,detailedFormatter
[logger_root]
level=WARNING
handlers=consoleHandler
[logger_mymodule]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=mymodule
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=defaultFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=handlers.RotatingFileHandler
level=INFO
formatter=detailedFormatter
args=('app.log','a',10485760,5)
[formatter_defaultFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
[formatter_detailedFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s
Python 代码里一行搞定:
import logging.config
logging.config.fileConfig('logging.ini')
logging.getLogger('mymodule').info("文件配置加载成功")
踩坑记录: fileConfig 默认不会加载 logging.handlers 里的类,如果你用 RotatingFileHandler,得在文件头的 [handler_fileHandler] 里把 class 写全:class=logging.handlers.RotatingFileHandler。
3.4 三种配置方式对比
| 配置方式 | 适用场景 | 灵活性 | 维护成本 | 我常用的理由 |
|---|---|---|---|---|
| basicConfig | 脚本、小工具、快速验证 | 低 | 低 | 写 Demo 时省心,但别上生产 |
| 字典配置 | 中大型项目、需要动态控制 | 高 | 中 | 可以按模块定制,无需额外文件 |
| 文件配置 | 团队项目、需要运维调整 | 中 | 低(文件维护) | 分离配置,改日志不用改代码 |
3.5 一张图理清配置关系
下面这张图展示了三种配置方式与核心组件(Logger、Handler、Formatter)之间的关系——你选择一种方式,最终都是把这些组件组装起来。我画图时习惯把「文件配置」单独拎出来,因为它多了一层配置文件读取。
我的建议: 开发阶段用字典配置,灵活调试;上生产后如果可以,改成文件配置,方便运维调整。如果你一个人写小项目,basicConfig 也不是不行,但记得别用它来写循环日志——文件会一直膨胀,直到磁盘爆掉。
3.6 实战经验:什么时候选哪种?
- 脚本/工具类 →
basicConfig+ 控制台输出,省事 - 小网站/微服务 → 字典配置,handler 分控制台和文件,方便调试和回查
- 大型微服务/分布式 → 文件配置 + 统一格式标准,团队每个人拉一份配置就能跑
三种配置方式没有的优劣,核心是理解配置的本质——告诉 logging 模块:什么日志该输出、用什么格式、写到哪儿。你掌握这三种,以后看任何框架的日志配置都不会懵。