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日志,导致最终无法输出。
两种解决方法:
- 修改根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)
- 禁用日志传播:在自定义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
相关产品推荐
相关产品推荐

