如何使用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
相关产品推荐
相关产品推荐

