You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多Python模块日志统一配置问题:logging.getLogger无法继承主模块日志配置导致日志未写入文件

Python模块日志统一配置问题:logging.getLogger无法继承主模块日志配置导致日志未写入文件

问题原因分析

从你的代码和输出来看,核心问题出在模块导入顺序错误,再加上对Python logging传播机制的细节理解不到位:

  1. 导入顺序颠倒:你在main.py里先执行了from utils import run,这会直接加载utils模块并创建子日志器logger = logging.getLogger(__name__),但此时根日志器还没有任何配置。后续你再调用logging.basicConfig()配置根日志时,已经创建好的子日志器不会自动同步根日志的新配置,导致日志传播出现异常。

  2. 默认级别遗留影响:Python根日志器的默认级别是WARNING,在你配置根日志之前,子日志器已经继承了这个默认级别。虽然之后你把根日志级别改成了DEBUG,但早期创建的子日志器没有及时感知到这个变化,导致INFO、DEBUG级别的日志被过滤掉,只有WARNING及以上级别能通过默认的控制台处理器输出。

  3. 潜在的导入遗漏:你的main.py代码里使用了os和time模块,但没有显式导入,这会直接抛出NameError,导致日志配置代码根本无法执行(如果你的实际代码里确实没加的话)。


修正方案

1. 调整导入顺序:先配置日志,再导入子模块

把日志配置代码放在所有子模块导入之前,这样子模块创建日志器时,根日志的配置已经生效,子日志器能正确通过传播机制复用根日志的处理器和级别。

修正后的main.py:

import os
import time
import logging

# 先完成日志配置,再导入子模块
log_path = './logs'
if not os.path.exists(log_path):
    os.makedirs(log_path)
# 用os.path.join拼接路径更安全,避免手动拼接的路径分隔符问题
full_log_path = os.path.join(
    log_path, 
    f'model-p2p_check-{time.strftime("%Y-%m-%d", time.localtime())}.log'
)

logging.basicConfig(
    level=logging.DEBUG,
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=[
        logging.FileHandler(full_log_path, 'w', 'utf-8'),
        logging.StreamHandler()
    ]
)

# 日志配置完成后,再导入子模块
from utils import run

run()

2. 子模块优化(可选,让配置更明确)

utils.py的代码不需要大改,默认的propagate=True会让子日志器把日志传递给根日志器处理。如果想让逻辑更清晰,可以显式设置子日志器的级别为NOTSET(默认就是这个值),确保完全继承根日志的级别:

修正后的utils.py:

import logging

# 创建子日志器,显式设置级别为NOTSET,确保继承根日志的级别
logger = logging.getLogger(__name__)
logger.setLevel(logging.NOTSET)

def run():
    logger.critical('Logger handlers: %s', logger.handlers)

    logger.info('This is an info message from the submodule.')
    logger.debug('This is a debug message')
    logger.info('This is an info message')
    logger.warning('This is a warning message')
    logger.error('This is an error message')
    logger.critical('This is a critical message')

修正后的效果

运行代码后,你会发现:

  • 所有级别的日志(DEBUG、INFO、WARNING等)都会同时输出到控制台和指定的日志文件中
  • logger.handlers仍然是空列表,这是正常的:子日志器没有自己的处理器,所有日志都会传播到根日志器的处理器中统一处理

额外的logging机制说明

  1. 日志传播规则:当子日志器没有自己的handlers且propagate=True时,日志会自动向上传递给父日志器,直到根日志器,由根日志器的处理器统一处理。
  2. 级别继承规则:子日志器默认级别为NOTSET,此时会使用父日志器的级别作为有效过滤级别;如果子日志器设置了自己的级别,则优先使用自身级别。

备注:内容来源于stack exchange,提问作者Carlos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:48:11