跳转至

四大核心组件:构建专业日志系统

期末考试重点:Python logging模块的四大核心组件(Logger、Handler、Formatter、Filter)是自动化测试框架的重要基础,必须深度理解它们的作用机制和协作关系。

四大组件架构图

Text Only
测试代码 → Logger(记录器) → Handler(处理器) → Formatter(格式器) → 输出目标
       Filter(过滤器)
    条件过滤处理

组件协作流程

  1. Logger:接收日志请求,判断级别是否满足条件
  2. Filter:对日志记录进行条件过滤(可选)
  3. Handler:决定日志的输出目标(控制台、文件等)
  4. Formatter:格式化日志消息的显示样式

1. Logger(记录器)- 日志系统的核心入口

核心职责

  • 接口提供者:为应用程序提供日志记录的直接接口
  • 级别控制者:决定哪些级别的日志会被处理
  • 层次管理者:支持父子继承关系的层次化管理
  • Handler协调者:管理和协调多个处理器

基础应用

Python
import logging

# 创建记录器
logger = logging.getLogger('automation_test')
logger.setLevel(logging.DEBUG)

# 记录不同级别的日志
logger.debug("详细调试信息")
logger.info("关键流程信息")
logger.warning("潜在问题警告")
logger.error("执行错误信息")
logger.critical("系统严重错误")

层次化管理(考试重点)

Python
# 父记录器
parent_logger = logging.getLogger('test_framework')
parent_logger.setLevel(logging.INFO)

# 子记录器(自动继承父记录器的配置)
selenium_logger = logging.getLogger('test_framework.selenium')
api_logger = logging.getLogger('test_framework.api')
database_logger = logging.getLogger('test_framework.database')

# 层次关系:test_framework ← test_framework.selenium ← test_framework.api

记录器管理最佳实践

Python
class LoggerFactory:
    """记录器工厂类 - 统一管理日志记录器"""

    _loggers = {}

    @classmethod
    def get_logger(cls, name, level=logging.INFO):
        """获取或创建记录器"""
        if name not in cls._loggers:
            logger = logging.getLogger(name)
            logger.setLevel(level)
            cls._loggers[name] = logger
        return cls._loggers[name]

    @classmethod
    def get_test_logger(cls, test_module):
        """获取测试模块专用记录器"""
        return cls.get_logger(f'test.{test_module}')

# 使用示例
login_logger = LoggerFactory.get_test_logger('login')
search_logger = LoggerFactory.get_test_logger('search')

2. Handler(处理器)- 输出目标的决策者

核心职责

  • 输出路由:决定日志记录的输出目标和方式
  • 级别过滤:每个处理器可独立设置日志级别
  • 格式应用:应用格式器对日志进行格式化
  • 并发支持:支持多个处理器同时工作

常用处理器类型

StreamHandler - 控制台输出

Python
import logging
import sys

# 标准输出处理器
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.INFO)

# 错误输出处理器
error_handler = logging.StreamHandler(sys.stderr)
error_handler.setLevel(logging.ERROR)

logger = logging.getLogger('test')
logger.addHandler(console_handler)
logger.addHandler(error_handler)

FileHandler - 基础文件输出

Python
import logging

# 基础文件处理器
file_handler = logging.FileHandler('test.log', encoding='utf-8')
file_handler.setLevel(logging.DEBUG)

# 追加模式文件处理器
append_handler = logging.FileHandler('test.log', mode='a', encoding='utf-8')

logger = logging.getLogger('test')
logger.addHandler(file_handler)

RotatingFileHandler - 大小轮转

Python
from logging.handlers import RotatingFileHandler

# 按文件大小轮转
rotating_handler = RotatingFileHandler(
    'test.log',                    # 文件名
    maxBytes=1024*1024*5,          # 最大5MB
    backupCount=3,                 # 保留3个备份
    encoding='utf-8'
)
rotating_handler.setLevel(logging.DEBUG)

# 文件轮转效果:test.log → test.log.1 → test.log.2 → test.log.3

TimedRotatingFileHandler - 时间轮转

Python
from logging.handlers import TimedRotatingFileHandler

# 按时间轮转
timed_handler = TimedRotatingFileHandler(
    'test.log',
    when='D',              # 轮转周期:H(小时)、D(天)、W(周)、M(月)
    interval=1,            # 每1天轮转
    backupCount=7,         # 保留7天的历史日志
    encoding='utf-8'
)
timed_handler.setLevel(logging.DEBUG)

多处理器协作策略

Python
def setup_multi_handler_system():
    """配置多处理器协作系统"""
    logger = logging.getLogger('automation')
    logger.setLevel(logging.DEBUG)
    logger.handlers.clear()

    # 1. 控制台处理器 - 显示重要信息
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)

    # 2. 调试文件处理器 - 记录所有详细信息
    debug_handler = RotatingFileHandler(
        'debug.log', maxBytes=10*1024*1024, backupCount=5, encoding='utf-8'
    )
    debug_handler.setLevel(logging.DEBUG)

    # 3. 错误文件处理器 - 专门记录错误
    error_handler = RotatingFileHandler(
        'error.log', maxBytes=5*1024*1024, backupCount=3, encoding='utf-8'
    )
    error_handler.setLevel(logging.ERROR)

    # 4. 添加所有处理器
    logger.addHandler(console_handler)
    logger.addHandler(debug_handler)
    logger.addHandler(error_handler)

    return logger

3. Formatter(格式器)- 输出样式的美化师

核心职责

  • 信息组织:决定日志消息的显示格式和内容布局
  • 时间格式化:控制时间戳的显示样式
  • 字段选择:选择要显示的日志字段信息
  • 可读性优化:提高日志的可读性和专业性

格式化字段说明(考试重点)

字段名 含义 示例
%(asctime)s 时间戳 2024-01-15 14:30:25
%(levelname)s 日志级别 INFO、ERROR
%(name)s 记录器名称 test.login
%(filename)s 文件名 test_login.py
%(lineno)d 行号 25
%(funcName)s 函数名 test_valid_login
%(message)s 日志消息 登录测试执行成功
%(pathname)s 文件完整路径 /tests/test_login.py
%(module)s 模块名 test_login

实用格式器配置

Python
import logging

# 1. 简洁格式器 - 适合控制台
simple_formatter = logging.Formatter(
    '%(levelname)s - %(message)s'
)

# 2. 标准格式器 - 适合一般文件记录
standard_formatter = logging.Formatter(
    '%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# 3. 详细格式器 - 适合调试文件
detailed_formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s() - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# 4. 错误格式器 - 包含异常信息
error_formatter = logging.Formatter(
    '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s\n%(exc_info)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

自定义格式器

Python
class CustomFormatter(logging.Formatter):
    """自定义格式器 - 添加特殊功能"""

    def format(self, record):
        # 添加自定义字段
        record.test_case = getattr(record, 'test_case', 'unknown')
        record.test_step = getattr(record, 'test_step', 'N/A')

        # 根据级别调整格式
        if record.levelno >= logging.ERROR:
            # 错误级别添加更多上下文信息
            self._style._fmt = '%(asctime)s - [%(test_case)s] - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
        else:
            # 普通级别使用简洁格式
            self._style._fmt = '%(asctime)s - %(levelname)s - %(message)s'

        return super().format(record)

# 使用自定义格式器
custom_formatter = CustomFormatter()
handler = logging.StreamHandler()
handler.setFormatter(custom_formatter)

4. Filter(过滤器)- 精准控制的守门员

核心职责

  • 条件过滤:基于自定义条件过滤日志记录
  • 动态控制:运行时动态调整过滤策略
  • 精细管理:比日志级别更精细的控制机制
  • 特殊场景:处理复杂的日志过滤需求

基础过滤器应用

Python
import logging

class TestCaseFilter(logging.Filter):
    """测试用例过滤器 - 只允许特定测试用例的日志"""

    def __init__(self, allowed_test_cases):
        super().__init__()
        self.allowed_test_cases = allowed_test_cases

    def filter(self, record):
        # 只允许指定测试用例的日志通过
        test_case = getattr(record, 'test_case', None)
        return test_case in self.allowed_test_cases

# 使用过滤器
test_filter = TestCaseFilter(['login_test', 'search_test'])
handler = logging.StreamHandler()
handler.addFilter(test_filter)

# 记录日志时添加测试用例信息
logger = logging.getLogger('test')
logger.addHandler(handler)

# 创建日志记录时添加额外信息
record = logging.LogRecord(
    name='test', level=logging.INFO, pathname='', lineno=0,
    msg='测试执行成功', args=(), exc_info=None
)
record.test_case = 'login_test'  # 添加自定义字段
logger.handle(record)

高级过滤器示例

Python
class PerformanceFilter(logging.Filter):
    """性能过滤器 - 过滤执行时间相关的日志"""

    def filter(self, record):
        # 只允许包含性能关键词的日志
        performance_keywords = ['timeout', 'slow', 'performance', 'duration']
        message = record.getMessage().lower()
        return any(keyword in message for keyword in performance_keywords)

class LevelRangeFilter(logging.Filter):
    """级别范围过滤器 - 只允许特定范围的日志级别"""

    def __init__(self, min_level, max_level):
        super().__init__()
        self.min_level = min_level
        self.max_level = max_level

    def filter(self, record):
        return self.min_level <= record.levelno <= self.max_level

# 应用示例:只记录WARNING到ERROR级别的日志
range_filter = LevelRangeFilter(logging.WARNING, logging.ERROR)
handler.addFilter(range_filter)

四大组件综合应用实例

Python
import logging
from logging.handlers import RotatingFileHandler
import sys

def setup_comprehensive_logging():
    """配置完整的四大组件协作系统"""

    # 1. 创建Logger
    logger = logging.getLogger('test_automation')
    logger.setLevel(logging.DEBUG)
    logger.handlers.clear()

    # 2. 创建Formatter
    console_formatter = logging.Formatter(
        '%(asctime)s - %(levelname)s - %(message)s',
        datefmt='%H:%M:%S'
    )

    file_formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(funcName)s() - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )

    # 3. 创建Handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(console_formatter)

    file_handler = RotatingFileHandler(
        'automation.log', maxBytes=5*1024*1024, backupCount=3, encoding='utf-8'
    )
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(file_formatter)

    # 4. 创建Filter
    class TestFilter(logging.Filter):
        def filter(self, record):
            # 过滤掉第三方库的DEBUG信息
            if record.levelno == logging.DEBUG and not record.name.startswith('test'):
                return False
            return True

    test_filter = TestFilter()
    file_handler.addFilter(test_filter)

    # 5. 组装系统
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)

    return logger

# 使用综合日志系统
logger = setup_comprehensive_logging()
logger.info("日志系统初始化完成")
logger.debug("这是调试信息")
logger.warning("这是警告信息")
logger.error("这是错误信息")

这四大组件的精密协作,构建了功能强大、灵活可控的日志系统,是自动化测试框架不可或缺的重要基础设施。