Python 多模块项目中如何正确使用 logging(各模块共用配置)?
Python 多模块日志最佳实践:每个模块 logger = logging.getLogger(__name__),只在程序入口配置一次(basicConfig 或 fileConfig),子 logger 自动继承配置。
标准模式:每个模块顶部写 logger = logging.getLogger(__name__)(不配置任何 handler);只在程序主入口配置一次 logging(basicConfig / fileConfig / dictConfig)。各模块的 logger 通过层级关系自动继承根配置。
各模块:只获取,不配置
# myapp/service.py
import logging
logger = logging.getLogger(__name__)
def process():
logger.info("开始处理")
__name__ 让 logger 名称自动等于模块路径(如 myapp.service),日志里一眼看出消息来自哪个模块。
主入口:配置一次
# main.py
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(name)s] %(levelname)s: %(message)s'
)
from myapp import service
service.process()
用配置文件管理(更灵活)
# main.py
import logging.config
logging.config.fileConfig('logging.conf')
logging.conf 示例:
[loggers]
keys=root
[handlers]
keys=console
[formatters]
keys=std
[logger_root]
level=INFO
handlers=console
[handler_console]
class=StreamHandler
formatter=std
[formatter_std]
format=%(asctime)s [%(name)s] %(levelname)s: %(message)s
常见错误
在模块里调用 basicConfig 或 addHandler——会导致重复输出、配置互相覆盖。模块只管 getLogger(__name__),配置交给入口。
常见问题(FAQ)
Q:子 logger 和根 logger 什么关系?
A:myapp.service 是 myapp 的子 logger,myapp 又是 root 的子 logger。消息默认沿层级向上传递(propagate),root 的 handler 会收到所有消息。
Q:想单独调某个模块的日志级别?
A:logging.getLogger('myapp.db').setLevel(logging.DEBUG)——只让 db 模块输出 DEBUG,其他模块保持 INFO。
Q:第三方库的日志太吵?
A:logging.getLogger('urllib3').setLevel(logging.WARNING),同样利用命名层级。