logging.basicconfig() 仅在 root logger 未配置时生效,若第三方库或提前日志调用已初始化 handler,则失效;需确保其为 import logging 后首条日志相关语句,或显式清空 handlers。

logging.basicConfig() 为什么总不生效
因为 basicConfig() 只在 root logger 尚未配置时才起作用。一旦你或某个第三方库(比如 requests、urllib3)提前调用了 logging.debug() 或初始化了 handler,它就彻底失效了。
- 检查是否在
import logging后立刻调用basicConfig(),且没有任何其他日志调用穿插其中 - 如果用了
pytest或某些框架(如 Flask),它们可能已预设 root logger,此时必须显式获取并重置:logging.getLogger().handlers.clear() -
basicConfig()对子 logger(如logging.getLogger("my.module"))无影响,子 logger 默认会向 root 传递日志——这是设计,不是 bug
DEBUG/INFO/WARNING/ERROR/CRITICAL 级别怎么选才不翻车
级别不是按“重要性”分的,而是按“事件发生时开发者需要介入的紧急程度”分的。INFO 不是“随便记点啥”,CRITICAL 也不等于“程序快崩了”。
-
DEBUG:仅开发/调试期启用,含变量值、函数入参、循环索引等临时信息;上线必须关闭(靠setLevel(logging.INFO)控制) -
INFO:用户可感知的正常流程节点,如"User 'alice' logged in"、"Starting backup job #123";避免写成"Got request"这种无意义废话 -
WARNING:非错误但需关注的情况,比如配置项缺失用默认值、API 返回了 404 但逻辑可兜底;不是“提醒你注意”,而是“这事本不该发生但程序还能跑” -
ERROR:发生了明确异常且无法恢复,比如数据库连接失败、文件读取权限被拒;要附带exc_info=True或手动捕获traceback.format_exc() -
CRITICAL:系统级故障,如磁盘满导致日志写入失败、核心配置加载失败致服务无法启动;极少用,慎用
Handler 写文件 vs 输出到 stdout 的真实取舍
本地开发用 StreamHandler(sys.stdout) 没问题,但一上容器或 systemd 就容易丢日志——stdout 被重定向、缓冲区未 flush、日志轮转缺失,全都会让你查不到东西。
- 生产环境优先用
RotatingFileHandler或TimedRotatingFileHandler,并设置backupCount=7和maxBytes=10485760(10MB)防磁盘打满 - 容器中若坚持输出 stdout,请确保
StreamHandler的stream是sys.stdout(不是sys.stderr),且 Python 启动加-u参数强制无缓冲 - 别在代码里硬编码路径如
"/var/log/myapp/app.log";用os.getenv("LOG_DIR", "/tmp")+os.path.join(),方便测试和容器挂载
logger = logging.getLogger(__name__) 中 __name__ 的坑
__name__ 看似省事,但模块名层级一深,比如 myproject.utils.db.helpers,日志前缀就会又长又难读,而且不同模块同名(如多个 utils.py)会导致 logger 实例混用。
立即学习“Python免费学习笔记(深入)”;
- 如果模块结构扁平(如
main.py、api.py、worker.py),直接用__name__安全 - 若存在嵌套包(
src/下多层目录),建议统一用短标识:logging.getLogger("db")、logging.getLogger("cache"),并在各模块开头显式定义常量LOGGER = logging.getLogger("db") - 切勿在函数内反复调用
getLogger()——它是轻量缓存的,但重复写降低可读性;也别用字符串拼接构造 logger 名,比如getLogger(f"{prefix}.worker"),会让日志归类和过滤变复杂
basicConfig(),而 handler 的生命周期(比如没 close)、formatter 的时间格式(默认不带毫秒)、以及多进程下 RotatingFileHandler 的竞态问题——这些都不在基础配置里,得单独处理。









