个人随笔
目录
LogCapture-日志捕获类-学习笔记
2026-02-03 23:07:06

一、笔记概述

本文是对自定义日志捕获处理器 LogCapture 类的详细解析笔记,该类基于 Python 内置 loggingio 模块,核心功能是将指定日志器的 INFO 级别及以上日志,重定向到内存中捕获(而非打印到控制台/文件),适用于日志验证、单元测试、日志二次处理等场景。

二、核心依赖

代码依赖 Python 内置模块,使用前需提前导入,否则会报 NameError

  1. import logging # 核心日志功能依赖
  2. import io # 内存字符串流(日志存储载体)依赖

三、类结构与核心方法解析

3.1 初始化方法 init(核心逻辑)

完成日志捕获的全部配置:创建存储载体、配置处理器、绑定日志器,逐行解析如下:

  1. def __init__(self):
  2. # 1. 创建内存字符串流,作为日志存储容器(替代控制台/文件)
  3. self.log_capture_string = io.StringIO()
  4. # 2. 创建流处理器,将日志输出定向到内存字符串流(核心重定向)
  5. self.log_handler = logging.StreamHandler(self.log_capture_string)
  6. # 3. 处理器级别:仅处理 INFO 及以上级别(INFO/WARNING/ERROR/CRITICAL)
  7. self.log_handler.setLevel(logging.INFO)
  8. # 4. 定义日志格式:时间-日志器名称-级别-消息(规范日志结构)
  9. self.log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  10. self.log_handler.setFormatter(self.log_formatter) # 绑定格式
  11. # 5. 绑定自定义日志器(qwen_agent_logger),设置级别并添加处理器
  12. self.logger = logging.getLogger('qwen_agent_logger')
  13. self.logger.setLevel(logging.INFO)
  14. self.logger.addHandler(self.log_handler)
  15. # 6. 绑定根日志器(全局默认日志器),捕获全局日志
  16. self.root_logger = logging.getLogger() # 无参数获取根日志器
  17. self.root_logger.setLevel(logging.INFO)
  18. self.root_logger.addHandler(self.log_handler)

关键原理:logging.StreamHandler 默认输出到控制台,传入 io.StringIO 对象后,实现日志的内存级重定向,这是捕获日志的核心。

3.2 get_log 方法(获取日志)

  1. def get_log(self):
  2. return self.log_capture_string.getvalue()
  • 功能:读取内存中存储的所有日志,返回字符串格式;

  • 特点:仅读取、不清空,多次调用返回相同结果。

3.3 clear_log 方法(清空日志)

  1. def clear_log(self):
  2. self.log_capture_string.truncate(0) # 截断流,清空内容
  3. self.log_capture_string.seek(0) # 指针移至开头,避免写入错位

注意:必须同时调用 truncate(0)seek(0),否则后续写入会出现空字符占位问题。

四、核心设计逻辑

  1. 双层日志捕获:同时绑定「自定义日志器 + 根日志器」,确保业务日志和全局日志都能被捕获;

  2. 级别双过滤:日志器和处理器均设置为 INFO 级别,只有同时高于两者级别的日志才会被捕获;

  3. 高效无开销:基于 io.StringIO 内存操作,无文件IO开销,适合高频捕获场景;

  4. 格式标准化:固定日志格式,便于后续解析、筛选日志内容。

五、关键注意事项(避坑重点)

5.1 避免重复添加处理器

多次创建 LogCapture 实例,会重复给日志器添加处理器,导致一条日志被多次捕获。

解决方案:初始化时清空日志器原有处理器:

  1. # 绑定日志器前添加清空操作
  2. self.logger = logging.getLogger('qwen_agent_logger')
  3. self.logger.handlers.clear() # 清空自定义日志器原有处理器
  4. self.root_logger = logging.getLogger()
  5. self.root_logger.handlers.clear() # 清空根日志器原有处理器

5.2 日志级别过滤规则

日志器级别 ≤ 处理器级别,处理器的级别过滤才会生效;若日志器级别高于处理器,会先过滤掉低级别日志(例:日志器设为 WARNING,处理器设为 INFO,无法捕获 INFO 日志)。

5.3 根日志器的全局影响

根日志器是全局共享的,修改其级别和处理器会影响整个项目的日志输出(包括第三方库日志)。若只需捕获业务日志,建议仅绑定 qwen_agent_logger,不要修改根日志器。

5.4 StringIO 生命周期

LogCapture 实例销毁时,内部 StringIO 也会被回收,需通过 get_log() 及时保存日志(如写入文件),避免丢失。

六、简单使用示例

  1. import logging
  2. import io
  3. class LogCapture:
  4. # 上述完整类代码...
  5. # 1. 创建日志捕获实例
  6. log_capture = LogCapture()
  7. # 2. 输出测试日志
  8. log_capture.logger.info('qwen_agent_logger 的 INFO 日志') # 自定义日志器
  9. logging.info('根日志器的 INFO 日志') # 根日志器
  10. logging.warning('根日志器的 WARNING 日志') # 高于 INFO 级别(会捕获)
  11. logging.debug('DEBUG 日志(会被过滤)') # 低于 INFO 级别(不捕获)
  12. # 3. 获取日志
  13. print("捕获的日志:")
  14. print(log_capture.get_log())
  15. # 4. 清空日志
  16. log_capture.clear_log()
  17. print("清空后日志:", log_capture.get_log()) # 输出空字符串
  18. # 5. 捕获新日志
  19. log_capture.logger.error('新的 ERROR 日志')
  20. print("新捕获日志:", log_capture.get_log())

七、总结

  1. 该类是轻量级、高性能的日志捕获工具,无外部依赖,核心是日志的内存重定向;

  2. 核心价值:脱离控制台/文件捕获日志,适合日志验证、单元测试等场景;

  3. 避坑关键:避免重复添加处理器、合理设置日志级别、谨慎修改根日志器。

    (注:文档部分内容可能由 AI 生成)

 5

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2