logging.getLogger(__name__) 是关键,因它基于模块名自动构建层级 logger 树,支持各模块独立设 level、handler 及 propagate=False,避免 root 干扰和日志重复或丢失。

为什么 logging.getLogger(__name__) 是关键
每个模块用 logging.getLogger(__name__) 获取独立 logger,而不是直接调用 logging.basicConfig() 或全局 logging.getLogger()。Python 的 logger 是按层级组织的(比如 a.b.c 是 a.b 的子 logger),__name__ 自动生成模块路径名,天然形成树状结构,为分级控制打下基础。
常见错误是全项目只用一个 root logger,结果改了某处级别,所有输出跟着变——这根本不是“不同模块不同级别”,只是全局开关。
如何给模块 A 设 INFO、模块 B 设 DEBUG
核心是分别获取、分别配置:不共享 handler,不共用 level,也不依赖 root 的传播(默认会向上传播到 root,造成干扰)。
- 在模块 A 开头写:
logger = logging.getLogger(__name__)logger.setLevel(logging.INFO)logger.addHandler(your_handler)logger.propagate = False # 关键!阻止向上送到 root - 在模块 B 开头写:
logger = logging.getLogger(__name__)logger.setLevel(logging.DEBUG)logger.addHandler(another_handler)logger.propagate = False - handler 可以复用(比如都用
StreamHandler),但 level 和 propagate 必须各自设
propagate=False 不设会怎样
如果不关掉 propagate,即使模块 B 的 logger 设了 DEBUG,它的日志仍会一路传到 root logger;而 root 默认是 WARNING 级别,结果 DEBUG 日志被 root 挡掉——你明明写了 logger.debug("test"),却什么也不输出,非常迷惑。
立即学习 “Python 免费学习笔记(深入)”;
更糟的是,如果 root 已配了 handler(比如 basicConfig 已执行),那模块日志会重复打印两次:一次走自己的 handler,一次走 root 的 handler。
所以只要不是有意做日志聚合,每个模块 logger 都该显式加一句 logger.propagate = False。
有没有更省事的集中配置方式
有,用 dictConfig 一次性定义多个 logger,适合中大型项目。但要注意:字典里必须显式写出每个 logger 的 "propagate": False,否则默认仍是 True。
例如配置模块 foo.bar 为 DEBUG、baz 为 WARNING:
{"version": 1, "loggers": { "foo.bar": { "level": "DEBUG", "handlers": ["console"], "propagate": False }, "baz": {"level": "WARNING", "handlers": ["file"], "propagate": False } } }
这种写法干净,但调试时不如逐模块设来得直观;一旦 dict 配错(比如漏写 propagate),问题会藏得比较深。






























