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

Python自定义Logger修改级别后无法输出DEBUG日志问题

问题

我创建了一个带有StreamHandler的自定义Python Logger,初始设置为logging.INFO级别,此时可正确隐藏DEBUG级别日志并输出INFO级别日志。编写了一个函数将Logger和Handler的级别均修改为logging.DEBUG,打印logger.getEffectiveLevel()和handler.level显示级别已成功变更,但仍仅能输出INFO级别日志,无法得到预期的DEBUG级别日志。已排查过类似问题帖,但均为根Logger配置问题,与我的情况不符。Python版本为3.8.6。

相关代码分为两部分:

主执行代码

logger = get_logger("my_logger") # 创建自定义Python logger

async def main():
    <...其他代码...>

    logger.debug("Before update")
    logger.info("Before update")
    print(f"{logger.name} - {logger.getEffectiveLevel()}")
    for handler in logger.handlers:
        print(f"{type(handler)} - {handler.level}")

    <...更新get_level()函数级别的代码...>

    update_log_levels() # 修改日志级别的函数

    print(f"{logger.name} - {logger.getEffectiveLevel()}")
    for handler in logger.handlers:
        print(f"{type(handler)} - {handler.level}")

    logger.debug("After update")
    logger.info("After update")

if __name__ == "__main__":
    asyncio.run(main())

自定义Logger代码

class CustomLogger(logging.Logger):
    def __init__(self, name: str, level: int):
        super().__init__(name, level)

        handler = logging.StreamHandler()
        handler.setLevel(level)
        handler.setFormatter(FORMATTER)
        self.addHandler(handler)

loggers = {}

def get_logger(name: str):
    level = get_level() # 获取级别的函数
    if name not in loggers.keys():
        loggers[name] = CustomLogger(name, level)

    return loggers[name]

def update_log_levels():
    for _, logger in loggers.items():
        level = get_level() # 获取级别的函数
        logger.setLevel(level)
        for handler in logger.handlers:
            handler.setLevel(level)

得到的输出:

2022-11-04 15:06:40,102 - my_logger - INFO     - Before update
my_logger - 20
<class 'logging.StreamHandler'> - 20
my_logger - 10
<class 'logging.StreamHandler'> - 10
2022-11-04 15:06:40,102 - my_logger - INFO     - After update

请问我遗漏了什么?

解决方案

问题出在根Logger的级别过滤上。Python logging模块的日志事件需要同时通过三层过滤:自定义Logger自身级别、Handler级别,以及所有祖先Logger(包括根Logger)的级别。

默认根Logger级别是logging.WARNING(值30),你的初始场景能输出INFO日志,说明根Logger被其他代码(比如你省略的<...其他代码...>)设置为了logging.INFO(值20)。当你把自定义Logger改为DEBUG级别后,日志事件会向上传递到根Logger,而根Logger的INFO级别会直接过滤掉DEBUG日志,导致最终无法输出。

两种解决方法:

  1. 修改根Logger级别:在更新日志级别的函数中同步调整根Logger的级别,确保它不会过滤自定义Logger的DEBUG日志:
def update_log_levels():
    root_logger = logging.getLogger()
    target_level = get_level()
    root_logger.setLevel(target_level)
    
    for _, logger in loggers.items():
        logger.setLevel(target_level)
        for handler in logger.handlers:
            handler.setLevel(target_level)
  1. 禁用日志传播:在自定义Logger的初始化方法中关闭propagate属性,阻止日志事件向上传递给根Logger,这样仅需自定义Logger和Handler的级别生效:
class CustomLogger(logging.Logger):
    def __init__(self, name: str, level: int):
        super().__init__(name, level)
        self.propagate = False  # 添加这一行
        
        handler = logging.StreamHandler()
        handler.setLevel(level)
        handler.setFormatter(FORMATTER)
        self.addHandler(handler)

内容的提问来源于stack exchange,提问作者btj29

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:30:58