如何让Python模块日志器适配任意主脚本日志器?
让Python模块日志自动继承主脚本日志器层级的解决方案
我明白你的需求:希望模块被任意脚本导入后,模块的日志器能自动挂靠在主脚本创建的日志器之下,不管主日志器是root还是自定义命名的(比如main)。这个问题的核心在于默认情况下,模块用__name__创建的日志器(比如module)父级是root,不会自动关联到主脚本的自定义日志器。
下面是具体的实现方案:
核心思路
通过动态检测主脚本中的主日志器,将模块日志器的名称设置为主日志器名称的子级(比如主日志器是main,模块日志器就设为main.module;主日志器是root,模块日志器设为.module),再配合自定义日志格式处理root的名称显示,就能实现你想要的输出效果。
具体代码实现
1. 模块文件 module.py
import logging import sys def get_main_logger(): """自动获取主脚本中的主日志器""" main_mod = sys.modules['__main__'] # 遍历主脚本的全局变量,找到第一个Logger实例 for name, obj in main_mod.__dict__.items(): if isinstance(obj, logging.Logger): return obj # 如果没找到,默认返回root日志器 return logging.getLogger() # 在模块导入时自动获取主日志器并创建子级日志器 main_logger = get_main_logger() if main_logger.name: mod_log_name = f"{main_logger.name}.{__name__}" else: # root日志器名称为空,模块日志器名称以点开头,方便后续格式替换 mod_log_name = f".{__name__}" mod_log = logging.getLogger(mod_log_name) def test(): mod_log.info("Test Mod")
2. 主脚本 a.py
import logging import module # 自定义日志格式,处理root名称为空和模块日志器名称的显示 class CustomFormatter(logging.Formatter): def format(self, record): if not record.name: # 将root日志器的空名称替换为"ROOT" record.name = 'ROOT' elif record.name.startswith('.'): # 将以点开头的模块日志器名称替换为"ROOT.xxx" record.name = 'ROOT' + record.name return super().format(record) # 配置主日志器(root) log = logging.getLogger() log.setLevel(logging.INFO) handler = logging.StreamHandler() handler.setFormatter(CustomFormatter('%(name)s - %(message)s')) log.addHandler(handler) log.info("Test Main") module.test()
3. 主脚本 b.py
import logging import module # 使用和a.py相同的自定义格式 class CustomFormatter(logging.Formatter): def format(self, record): if not record.name: record.name = 'ROOT' elif record.name.startswith('.'): record.name = 'ROOT' + record.name return super().format(record) # 配置自定义主日志器"main" log = logging.getLogger('main') log.setLevel(logging.INFO) handler = logging.StreamHandler() handler.setFormatter(CustomFormatter('%(name)s - %(message)s')) log.addHandler(handler) log.info("Test Main") module.test()
运行效果
- 执行
a.py,输出:ROOT - Test Main ROOT.module - Test Mod - 执行
b.py,输出:main - Test Main main.module - Test Mod
注意事项
- 如果主脚本中存在多个
logging.Logger实例,get_main_logger()会返回第一个找到的实例。如果需要更精确的控制,可以约定主日志器的变量名(比如固定用main_log),然后在函数中直接查找该变量。 - 确保主脚本的日志器在模块导入前或导入后创建都可以:如果先导入模块再创建日志器,
get_main_logger()会返回root(和主脚本的root一致);如果先创建日志器再导入模块,会直接找到该日志器。
内容的提问来源于stack exchange,提问作者Drew Aschenbrener
相关产品推荐
相关产品推荐

