pytest 如何在扩展的插件中修改日志格式

Python
151
0
0
2024-03-21
pytest 如何在扩展的插件中修改日志格式
  • pytest 日志格式配置
  • 如何在插件或者代码运行时修改日志格式
pytest 日志格式配置

Pytest 支持通过配置的方式修改日志格式,查看 pytest 帮助命令即可查看支持的配置参数。 其中与日志相关的配置有以下几项:

pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
logging:
  --log-level=LEVEL     level of messages to catch/display.
                        Not set by default, so it depends on the root/parent log handler's effective level, where it is "WARNING" by default.
  --log-format=LOG_FORMAT
                        log format as used by the logging module.
  --log-date-format=LOG_DATE_FORMAT
                        log date format as used by the logging module.
  --log-cli-level=LOG_CLI_LEVEL
                        cli logging level.
  --log-cli-format=LOG_CLI_FORMAT
                        log format as used by the logging module.
  --log-cli-date-format=LOG_CLI_DATE_FORMAT
                        log date format as used by the logging module.
  --log-file=LOG_FILE   path to a file when logging will be written to.
  --log-file-level=LOG_FILE_LEVEL
                        log file logging level.
  --log-file-format=LOG_FILE_FORMAT
                        log format as used by the logging module.
  --log-file-date-format=LOG_FILE_DATE_FORMAT
                        log date format as used by the logging module.
  --log-auto-indent=LOG_AUTO_INDENT
                        Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.

[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:
  log_level (string):   default value for --log-level
  log_format (string):  default value for --log-format
  log_date_format (string):
                        default value for --log-date-format
  log_cli (bool):       enable log display during test run (also known as "live logging").
  log_cli_level (string):
                        default value for --log-cli-level
  log_cli_format (string):
                        default value for --log-cli-format
  log_cli_date_format (string):
                        default value for --log-cli-date-format
  log_file (string):    default value for --log-file
  log_file_level (string):
                        default value for --log-file-level
  log_file_format (string):
                        default value for --log-file-format
  log_file_date_format (string):
                        default value for --log-file-date-format
  log_auto_indent (string):
                        default value for --log-auto-indent

pytest 支持在命令行中指定日志参数格式,例pytest --log-format="%(asctime)s %(levelname)s [%(filename)s:%(lineno)s] %(message)s" --log-date-format="%Y-%m-%d %H:%M:%S" 也支持pytest.ini文件配置

[pytest]
log_cli = True
log_cli_level = DEBUG
log_date_format = %Y-%m-%d %H:%M:%S
log_format = %(asctime)s %(levelname)s [%(filename)s:%(lineno)s] %(message)s

具体配置的方法参考:https://docs.pytest.org/en/7.1.x/reference/customize.html#command-line-options-and-configuration-file-settings

如何在插件或者代码运行时修改日志格式

我碰到的一种场景是,我们自己开发了一个集成了实际业务场景的pytest插件pytest-XXX,这个对接了几十个测试项目,现在想要修改测试报告中的日志格式。 如果按照官方的配置进行修改的话,那么需要修改N多项目,并且无法保证没有修改遗漏,并且以后新增的项目也需要增加这个配置。

那么如何在插件中修改pytest的日志格式呢?

走读pytest源码 https://docs.pytest.org/en/7.1.x/_modules/_pytest/logging.html 发现 pytest 的loggging模块中,声明了通过hook的方式注册了一个日志插件 logging-plugin,而这个日志插件正是pytest打印日志的插件

@hookimpl(trylast=True)
def pytest_configure(config: Config) -> None:
    config.pluginmanager.register(LoggingPlugin(config), "logging-plugin")


class LoggingPlugin:
    """Attaches to the logging module and captures log messages for each test."""

    def __init__(self, config: Config) -> None:
        # Report logging.
        self.formatter = self._create_formatter(
            get_option_ini(config, "log_format"),
            get_option_ini(config, "log_date_format"),
            get_option_ini(config, "log_auto_indent"),
        )
        ...
        self.log_level = get_log_level_for_setting(config, "log_level")
        self.caplog_handler = LogCaptureHandler()
        self.caplog_handler.setFormatter(self.formatter)
        self.report_handler = LogCaptureHandler()
        self.report_handler.setFormatter(self.formatter)
        ...
        self.log_cli_handler = _LiveLoggingNullHandler()
        ...

知道了原理之后,那么我们就可以在加载我们插件(pytest-XXX)的地方,动态修改pytest注册的logging插件中的日志输出格式配置。

# 配置文件
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
    mgr = config.pluginmanager
    logging_plugin = mgr.get_plugin("logging-plugin")
    log_formatter = logging_plugin._create_formatter(
        "%(asctime)s %(levelname)s [%(filename)s:%(lineno)s] %(message)s",
        "%Y-%m-%d %H:%M:%S",
        False,
    )
    logging_plugin.log_cli_handler.setFormatter(log_formatter)
    logging_plugin.caplog_handler.setFormatter(log_formatter)
    logging_plugin.report_handler.setFormatter(log_formatter)

这样,无论前面配置生成的logging handler 格式如何,最终的日志格式都会被修改为我们预期的格式。