Python Logging 配置了 filename 却没有生成日志文件的原因与解决方法

1. 问题现象

在 Python 中我们常用
logging.basicConfig()
来初始化日志。例如:



import logging
 
log_file = "save/logging/app.log"
 
logging.basicConfig(
    filename=log_file,
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    filemode="w"
)
 
logging.info("程序启动")

正常情况下,执行后会在
save/logging/
目录下生成
app.log
文件,并写入日志内容。

但在实际开发中,可能会遇到这样的问题:

没有报错

目录存在

调用了
logging.info()
等方法

结果就是
.log
文件没有生成

这就让人很困惑:明明代码和之前一样,为什么突然就不写日志了?


2. 原因分析:
logging.basicConfig()
的机制

要理解这个现象,需要知道
basicConfig()
的内部机制。

2.1
basicConfig()
只生效一次


logging.basicConfig()
的作用是为 root logger 配置默认的 handler 和 formatter。

但它有一个“保护机制”:只有在 root logger 上没有任何 handler 时才会生效

一旦 root logger 已经存在 handler,再调用
basicConfig()
就会 直接返回,不做任何事

2.2 为什么会“突然不生效”?

在很多项目里,可能你在调用
basicConfig()
之前,某个第三方库已经用过 logging 了。
常见的库比如:


requests


matplotlib


flask


sqlalchemy

……

这些库在 import 或使用时,可能会触发 logging,从而自动给 root logger 添加一个默认的
StreamHandler
(输出到控制台)。

这样一来:

root logger 上已经有 handler 了

再调用
basicConfig(filename=...)
就会被忽略

结果就是:日志既不会写入文件,也不会报错

2.3 为什么没有报错?

logging 的设计理念是“尽量不中断业务逻辑”。
因此,当
basicConfig()
被忽略时,它不会提示你,也不会抛出异常,只是悄悄不生效。

这就是为什么会出现「没有文件、也没有报错」的现象。


3. 解决方法

既然问题的根源是:
basicConfig()
只有在 root logger 没有 handler 时才生效,那对应的解决方法就很明确了。

方法一:在调用
basicConfig()
前清理 handler



import logging, os
 
log_file = "save/logging/app.log"
os.makedirs(os.path.dirname(log_file), exist_ok=True)
 
# 清理 root logger 已有的 handler
for h in logging.root.handlers[:]:
    logging.root.removeHandler(h)
 
logging.basicConfig(
    filename=log_file,
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    filemode="w"
)
 
logging.info("日志系统启动成功")

这样可以确保
basicConfig()
一定会生效。


方法二:不用
basicConfig
,手动添加
FileHandler

在生产代码中,更推荐直接手动配置 logger,而不是依赖
basicConfig



import logging, os
 
log_file = "save/logging/app.log"
os.makedirs(os.path.dirname(log_file), exist_ok=True)
 
logger = logging.getLogger()   # 获取 root logger
logger.setLevel(logging.INFO)
 
# 避免重复添加 handler
if not any(isinstance(h, logging.FileHandler) for h in logger.handlers):
    fh = logging.FileHandler(log_file, mode="w", encoding="utf-8")
    formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
    fh.setFormatter(formatter)
    logger.addHandler(fh)
 
logger.info("日志系统启动成功")

这种方式更可控,避免了
basicConfig()
的“只生效一次”陷阱。


4. 总结


logging.basicConfig()
只在 root logger 没有 handler 时才会生效

如果你发现配置了
filename
却没有生成日志文件,大概率是因为 某个库先触发了 logging,导致 root logger 已经有 handler

解决方法有两个:

清理 root logger 的 handler 后再调用
basicConfig()

不依赖
basicConfig()
,直接手动配置
FileHandler

👉 在实际项目中,推荐 方法二:手动添加
FileHandler
,可控性更高,也能避免掉这个常见坑。


© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
是幸运大门啊的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容