You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Pytest Caplog测试自定义日志脱敏格式化器?

Pytest测试自定义日志脱敏格式化器的解决方案

我通过自定义日志格式化器RedactFoo对日志中的敏感内容(示例中用"foo"代替)进行脱敏,正常运行时日志能正确替换内容,但使用Pytest的caplog fixture测试时,由于Pytest默认覆盖了自定义日志配置,导致测试无法验证脱敏效果。以下是三种可行的Pytest解决方案:

方案1:手动为caplog的handler替换自定义格式化器

直接获取caplog对应的handler,将其格式化器替换为RedactFoo包装后的实例,确保日志捕获时应用脱敏逻辑。

示例代码

my_logger.py

import logging

class RedactFoo(logging.Formatter):
    def __init__(self, formatter):
        self.formatter = formatter

    def format(self, record):
        # 脱敏逻辑:替换"foo"为***
        original_msg = self.formatter.format(record)
        return original_msg.replace("foo", "***")

def get_redacted_logger():
    logger = logging.getLogger("my_logger")
    logger.setLevel(logging.INFO)
    # 基础格式化器
    base_formatter = logging.Formatter("%(message)s")
    # 包装为脱敏格式化器
    redact_formatter = RedactFoo(base_formatter)
    handler = logging.StreamHandler()
    handler.setFormatter(redact_formatter)
    logger.addHandler(handler)
    return logger

test_my_logger.py

import logging
from my_logger import RedactFoo, get_redacted_logger

def test_redact_log_with_caplog(caplog):
    # 替换caplog handler的格式化器为脱敏版本
    base_formatter = logging.Formatter("%(message)s")
    caplog.handler.setFormatter(RedactFoo(base_formatter))
    
    logger = get_redacted_logger()
    logger.info("This is a foo message")
    
    # 验证脱敏结果
    assert "This is a *** message" in caplog.text

方案2:通过pytest全局配置指定自定义格式化器

在项目根目录的conftest.py中使用pytest_configure钩子,全局配置日志格式化器,让caplog默认使用脱敏逻辑。

示例代码

conftest.py

import logging
from my_logger import RedactFoo

def pytest_configure(config):
    # 定义基础格式化器并包装为脱敏版本
    base_formatter = logging.Formatter("%(levelname)s: %(message)s")
    redact_formatter = RedactFoo(base_formatter)
    
    # 为所有根日志handler替换格式化器
    for handler in logging.root.handlers:
        handler.setFormatter(redact_formatter)

test_my_logger.py

from my_logger import get_redacted_logger

def test_redact_log_global_config(caplog):
    logger = get_redacted_logger()
    logger.info("This is a foo message")
    
    assert "This is a *** message" in caplog.text

方案3:绕过caplog,手动配置日志捕获

如果不想修改caplog的默认行为,可以手动创建内存handler,添加到目标logger上,直接捕获并验证日志内容。

示例代码

import logging
from io import StringIO
from my_logger import RedactFoo, get_redacted_logger

def test_redact_log_manual_capture():
    # 创建内存handler用于捕获日志
    stream = StringIO()
    base_formatter = logging.Formatter("%(message)s")
    redact_formatter = RedactFoo(base_formatter)
    handler = logging.StreamHandler(stream)
    handler.setFormatter(redact_formatter)
    
    logger = get_redacted_logger()
    logger.addHandler(handler)
    
    logger.info("This is a foo message")
    
    # 获取并验证日志内容
    log_output = stream.getvalue().strip()
    assert log_output == "This is a *** message"

内容的提问来源于stack exchange,提问作者it's-yer-boy-chet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:57:16