logging.basicconfig() 在 root logger 已配置 handler 后失效,因它仅在未初始化时生效;需置于所有 import 前或使用 force=true(python 3.8+);多模块应通过命名 logger 分级控制,避免依赖 root;多进程须用 queuehandler 或 concurrent_log_handler 等线程/进程安全方案。

logging.basicConfig() 为什么在导入模块后就失效了
因为 basicConfig() 只有在 root logger 尚未配置过 handler 时才生效。一旦任意模块(比如第三方库)提前调用了 logging.info() 或显式配置了 handler,root logger 就被“污染”了,后续的 basicConfig() 直接静默退出——不报错,也不生效。
- 典型触发场景:
import requests、import scrapy、甚至某些包的__init__.py里偷偷打了一条日志 - 验证方法:执行
import logging; print(logging.getLogger().handlers),非空即已初始化 - 正确做法:把
basicConfig()放在所有 import 之前;或改用force=True(Python 3.8+)强制重置
多个模块共享 logging 配置但各自要不同级别怎么办
不能靠反复调 basicConfig(),得用 logger 实例分级控制。root logger 负责输出,子 logger 负责过滤——这是 logging 的设计前提。
- 子 logger 默认继承 root 的 handler,但可独立设
level:比如logging.getLogger('myapp.db').setLevel(logging.DEBUG) - 避免用
logging.getLogger()(返回 root),始终用带名字的logging.getLogger('xxx')获取命名 logger - 注意传播(
propagate):设为False可阻止日志向上送到 root,否则可能重复打印
用 dictConfig() 加载 YAML/JSON 配置时路径不生效
常见于 filename 指向相对路径,但实际工作目录(os.getcwd())和配置文件所在目录不一致,导致日志写入失败或生成在意外位置。
- 错误写法:
'filename': 'logs/app.log'—— 路径基于当前工作目录解析 - 安全写法:用
pathlib.Path(__file__).parent / 'logs' / 'app.log'拼出绝对路径,再转成字符串传入 - dictConfig 不会自动创建父目录,
os.makedirs(os.path.dirname(path), exist_ok=True)得自己加
多进程下 logging.FileHandler 写入混乱或报错
FileHandler 不是进程安全的。多个进程同时 open 同一个文件,轻则日志交错,重则抛 OSError: [Errno 24] Too many open files。
立即学习“Python免费学习笔记(深入)”;
- 开发/单进程场景可用
RotatingFileHandler,但生产多进程必须换方案 - 推荐:用
QueueHandler+ 单独日志进程,或直接上concurrent_log_handler这类第三方轮子 - 别用
TimedRotatingFileHandler在多进程下做 rollover——时间判断和 rename 操作无法同步
logging.warning(),就能让主程序的 basicConfig() 彻底失能——这种依赖关系看不见、摸不着,只能靠提前检查 root.handlers 和严格约束 import 顺序来防。










