Pytest中结合Allure报告添加logging的优化方案咨询
问题描述
我用如下静态方法给Allure报告添加步骤:
import allure from datetime import datetime class Report: @staticmethod def report_step(step_title): with allure.step(f'[{datetime.now()}]: {step_title}'): pass
尝试加入logging功能后修改为:
def report_step(step_title): m = f'[{datetime.now()}]: {step_title}' with allure.step(m): logging.debug(m)
但存在两个问题:
- 无法灵活指定日志级别(虽可添加参数,但仍需更优方式);
- 日志格式为
'[%(asctime)s] [ %(levelname)s ] [%(filename)s] [%(funcName)s] [%(lineno)d]: %(message)s',但所有日志条目均来自Report类,无法定位实际调用位置。
解决方案
1. 灵活配置日志级别
给report_step方法添加log_level参数,默认设为logging.DEBUG,直接映射logging的级别常量,调用时可按需传入不同级别。
2. 定位实际调用位置
利用inspect模块获取调用者的栈帧信息,跳过当前Report类的栈帧,将调用者的文件名、行号、函数名传递给日志系统,让日志格式显示实际调用代码的位置。
方案一:直接在方法内获取调用者信息
修改后的完整代码:
import allure import logging from datetime import datetime import inspect class Report: @staticmethod def report_step(step_title, log_level=logging.DEBUG): step_msg = f'[{datetime.now()}]: {step_title}' # 获取调用者的栈帧信息 caller_frame = inspect.currentframe().f_back caller_filename = caller_frame.f_code.co_filename caller_lineno = caller_frame.f_lineno caller_func = caller_frame.f_code.co_name with allure.step(step_msg): logger = logging.getLogger(__name__) # 通过extra参数传递调用者信息,覆盖日志默认的位置信息 logger.log( level=log_level, msg=step_msg, extra={ 'filename': caller_filename, 'funcName': caller_func, 'lineno': caller_lineno } )
调用示例:
# 默认DEBUG级别 Report.report_step("初始化测试环境") # 指定INFO级别 Report.report_step("用户登录操作", log_level=logging.INFO)
方案二:自定义日志过滤器(更优雅的全局处理)
如果多个地方需要处理这种调用者日志,可以自定义日志过滤器,统一跳过Report类的栈帧:
import logging import inspect class CallerFilter(logging.Filter): def filter(self, record): frame = inspect.currentframe() try: # 跳过filter、log方法、report_step三层栈帧,定位到实际调用者 for _ in range(3): frame = frame.f_back record.filename = frame.f_code.co_filename record.funcName = frame.f_code.co_name record.lineno = frame.f_lineno finally: # 手动删除帧对象,避免内存泄漏 del frame return True # 给全局日志器添加过滤器 root_logger = logging.getLogger() root_logger.addFilter(CallerFilter())
此时Report类的方法可以简化为:
import allure import logging from datetime import datetime class Report: @staticmethod def report_step(step_title, log_level=logging.DEBUG): step_msg = f'[{datetime.now()}]: {step_title}' with allure.step(step_msg): logging.log(log_level, step_msg)
两种方案都能实现:
- 按需指定日志级别,满足不同场景的日志输出需求;
- 日志格式中的位置信息将显示实际调用
report_step的代码位置,而非Report类内部。
内容的提问来源于stack exchange,提问作者Ran Pol
相关产品推荐
相关产品推荐

