python+pytest+loguru+allure日志封装
一、日志类封装
1 from io import StringIO 2 import sys 3 import os 4 from loguru import logger 5 sys.path.append((os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))) 6 project_path = os.path.dirname(os.path.join(os.path.dirname(__file__))) 7 log_path = os.path.join(project_path, r'common\logger_info') 8 9 class Logconfig: 10 def __init__(self, log_file_dir='logger_info',log_name='case_log_info.log',level='DEBUG',rotation="10 MB", retention="7 days"): 11 """ 12 log日志封装 13 :param log_file_dir: 日志路径 14 :param log_name: 日志名称 15 :param level: 日志输出等级 16 :param rotation: 日志保存大小 17 :param retention: 日志保存时间 18 """ 19 # 创建日志输出路径 20 self.log_file_dir = log_file_dir 21 if not os.path.exists(self.log_file_dir): 22 os.makedirs(self.log_file_dir) 23 24 # 配置日志 25 self.level = level 26 self.rotation = rotation 27 self.retention = retention 28 29 # 配置日志写入文件路径 30 self.log_file_dir = os.path.join(self.log_file_dir, log_name) 31 print('日志写入路径:',self.log_file_dir) 32 33 # 创建一个缓冲区用于捕获日志 34 self.log_capture = StringIO() 35 36 # 调用日志配置方法 37 self.logconfig() 38 39 def logconfig(self): 40 # 清除默认配置 41 logger.remove() 42 # 配置日志输出到控制台 43 logger.add( 44 sink=sys.stdout, 45 format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> |{module}.{function}() at line {line}-{message}", 46 level=self.level 47 ) 48 49 # 配置日志输出到文件 50 logger.add( 51 sink=self.log_file_dir, 52 format = "{time:YYYY-MM-DD HH:mm:ss} |{level: <8} | {module}.{function}() at line {line}-{message}", 53 level = self.level, 54 rotation = self.rotation, 55 retention = self.retention, 56 encoding = "utf-8", 57 colorize=True 58 ) 59 # 配置日志输出到缓冲区 60 logger.add( 61 sink=self.log_capture, 62 format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {module}.{function}() at line {line}-{message}", 63 level=self.level 64 ) 65 66 # 获取捕获的日志内容 67 def get_captured_logs(self): 68 self.log_capture.seek(0) 69 return self.log_capture.getvalue() 70 71 72 # 获取logger实例 73 def get_logger(self): 74 75 return logger 76 77 if __name__ == '__main__': 78 loggerconfig_info = Logconfig(log_file_dir=log_path, log_name='case_log_info.log', level='DEBUG') 79 logger = loggerconfig_info.get_logger() 80 81 logger.debug('调试日志') 82 logger.info('普通日志') 83 logger.warning('告警日志') 84 logger.error('错误日志') 85 86 # 将捕获的日志附加到 Allure 报告 87 # captured_logs = loggerconfig_info.get_captured_logs() 88 # allure.attach(captured_logs, name="Test Logs", attachment_type=allure.attachment_type.TEXT) 89 90 91 测试用例调用: 92 方法一: 93 用例中实例化logger 94 from common.log_info import Logconfig,log_path 95 logger = Logconfig(log_file_dir=log_path).get_logger() 96 @pytest.mark.parametrize('a,b,c', [(1, 2, 3), (4, 5, 6)]) 97 def test_01(a, b,c): 98 with allure.step('test01'): 99 logger.info('测试case01') 100 print(f"传入的参数分别是:{a},{b},{c}") 101 102 方法二: 103 将封装好的Logconfig类在conftest中写成fixture自动执行 104 import allure 105 from common.log_info import log_path,Logconfig 106 @pytest.fixture(scope="function",autouse=True) 107 def log_test_infooo(): 108 logger_config = Logconfig(log_file_dir=log_path, log_name='case_log_info.log', level='DEBUG') 109 logger = logger_config.get_logger() 110 111 yield logger 112 113 captured_logs = logger_config.get_captured_logs() 114 allure.attach(captured_logs, name="Test Logs", attachment_type=allure.attachment_type.TEXT) scope="function" 作用域测试函数 autouse=True 自动执行不需要在用例中显式调用
118 from loguru import logger 119 @pytest.mark.parametrize('a,b,c', [(1, 2, 3), (4, 5, 6)]) 120 def test_01(a, b,c): 121 with allure.step('test01'): 122 logger.info('测试case01') 123 print(f"传入的参数分别是:{a},{b},{c}")
二、conftest中通过fixture输出日志
1 import os 2 from loguru import logger 3 @pytest.fixture(scope="function",autouse=True) 4 def configure_logger(): 5 # 配置 loguru 输出到文件 6 log_dir = "logs" 7 if not os.path.exists(log_dir): 8 os.makedirs(log_dir) 9 log_file = os.path.join(log_dir, "test.log") 10 logger.add(log_file, format="{time} {level} {module}.{function}() at line {line}-{message}", level="DEBUG",encoding="utf-8") 11 12 yield 13 # 测试结束后,将日志文件附加到 Allure 报告中 14 with open(log_file, "r", encoding="utf-8") as f: 15 allure.attach(f.read(), name="Test Logs", attachment_type=allure.attachment_type.TEXT)scope="function" 作用域测试函数autouse=True 自动执行不需要在用例中显式调用
# 用例调用
from loguru import logger
@pytest.mark.parametrize('a,b,c', [(1, 2, 3), (4, 5, 6)])
def test_01(a, b,c):
with allure.step('test01'):
logger.info('测试case01')
print(f"传入的参数分别是:{a},{b},{c}")
执行后日志文件写入:
2025-03-28T10:36:32.414692+0800 INFO test_sz.test_01() at line 35-测试case01
2025-03-28T10:36:32.424637+0800 INFO test_sz.test_01() at line 35-测试case01
2025-03-28T10:36:32.424637+0800 INFO test_sz.test_01() at line 35-测试case01
终端日志打印:
testcase/test_sz.py::test_01[1-2-3] 2025-03-28 10:38:09.512 | INFO | testcase.test_sz:test_01:35 - 测试case01
传入的参数分别是:1,2,3
PASSED
testcase/test_sz.py::test_01[4-5-6] 2025-03-28 10:38:09.519 | INFO | testcase.test_sz:test_01:35 - 测试case01
传入的参数分别是:4,5,6
PASSED
allure报告中附件日志信息:

如果想每个case日志在allure报告中单独展示,修改fixture方法:
@pytest.fixture(scope="function", autouse=True) def configure_logger(request): log_dir = "logs" if not os.path.exists(log_dir): os.makedirs(log_dir) log_file = os.path.join(log_dir, f"{request.node.name}.log") # 使用测试名称作为日志文件名 logger.remove() logger.add(log_file, format="{time} {level} {module}.{function}() at line {line}-{message}", level="DEBUG", encoding="utf-8") yield with open(log_file, "r", encoding="utf-8") as f: allure.attach(f.read(), name="Test Logs", attachment_type=allure.attachment_type.TEXT)

浙公网安备 33010602011771号