多模块Python包日志切换:主程序与API导入时的日志策略实现
优雅实现Python包的日志动态配置
核心思路
利用Python日志模块的层级继承特性,包内所有子模块通过__name__获取日志器,自动继承根日志器的配置。只需在main.py中根据运行场景(直接执行/被导入)动态配置根日志器,无需在各模块重复配置或传递日志器,完美避开多日志器写同一文件的问题。
具体实现步骤
1. 包内子模块的日志使用规范
所有子模块统一用logging.getLogger(__name__)获取日志器,不需要额外配置:
# 示例:包内的module_a.py import logging logger = logging.getLogger(__name__) def do_something(): logger.info("模块A执行了核心操作")
2. main.py中的动态配置逻辑
通过__name__ == "__main__"判断运行模式,结合命令行参数决定日志输出方式:
import logging import argparse from my_package import module_a, module_b def setup_logging(log_file=None): # 获取根日志器,统一管理所有子模块的日志配置 root_logger = logging.getLogger() root_logger.setLevel(logging.INFO) # 清空已有处理器,避免重复添加导致日志重复输出 for handler in root_logger.handlers[:]: root_logger.removeHandler(handler) # 配置控制台输出处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") console_handler.setFormatter(formatter) root_logger.addHandler(console_handler) # 如果传入日志文件参数,添加文件输出处理器 if log_file: file_handler = logging.FileHandler(log_file, encoding="utf-8") file_handler.setLevel(logging.INFO) file_handler.setFormatter(formatter) root_logger.addHandler(file_handler) if __name__ == "__main__": # 解析命令行的日志文件参数 parser = argparse.ArgumentParser() parser.add_argument("--log-file", help="日志输出文件的路径") args = parser.parse_args() # 初始化日志配置 setup_logging(args.log_file) # 调用包内模块的功能 module_a.do_something() module_b.do_something_else() else: # 当包被其他代码导入时,仅配置控制台输出 setup_logging()
方案优势
- 无需传递日志器:子模块通过层级继承自动复用根日志器配置,符合Python日志模块的设计规范。
- 避免文件句柄冲突:仅根日志器添加文件处理器,所有子模块日志统一通过该处理器输出,不会出现多进程写同一文件的问题。
- 场景自动适配:通过
__name__判断运行模式,自动切换日志配置,逻辑简洁清晰。 - 配置集中可控:所有日志配置逻辑都在
setup_logging函数中,后续修改格式、级别等只需调整这一处。
注意事项
- 子模块中不要自行添加日志处理器,否则会破坏继承关系,导致日志重复输出。
- 如果需要某子模块单独设置日志级别,直接在子模块中写
logger.setLevel(logging.DEBUG)即可,不会影响其他模块的配置。
内容的提问来源于stack exchange,提问作者Olga
相关产品推荐
相关产品推荐

