如何在pytest中抑制第三方日志

问题描述

我们刚刚从 nose 切换到 pytest,并且似乎没有抑制第三方日志记录的选项。在 nose 配置中,我们有以下行:

logging-filter=-matplotlib,-chardet.charsetprober,-PIL,-fiona.env,-fiona._env

其中一些日志非常啰嗦,尤其是 matplotlib,我们不想看到输出,只想从日志中输出

不过我在 pytest 中找不到等效的设置。是否有可能?我错过了什么吗?谢谢。

解决方法

我这样做的方法是创建一个记录器名称列表,必须在 conftest.py 中为其禁用日志。

例如,如果我想禁用一个名为 app 的记录器,那么我可以编写一个 conftest.py 如下:

import logging

disable_loggers = ['app']

def pytest_configure():
    for logger_name in disable_loggers:
        logger = logging.getLogger(logger_name)
        logger.disabled = True

然后运行我的测试:

import logging

def test_brake():
    logger = logging.getLogger("app")
    logger.error("Hello there")
    assert True

正在收集……收集了 1 个项目

test_car.py::test_brake PASSED
[100%]

============================== 1 在 0.01 秒内通过 ============ ====================

然后,你好不在那里,因为名称为 app 的记录器在 conftest.py 中被禁用。

但是,如果我将测试中的记录器名称更改为 app2 并再次运行测试:

import logging

def test_brake():
    logger = logging.getLogger("app2")
    logger.error("Hello there")
    assert True

正在收集……收集了 1 个项目

test_car.py::test_brake -------------------------------- 实时日志调用 --------------- ------------------ 错误 app2:test_car.py:5 你好 PASSED
[100%]

============================== 1 在 0.01 秒内通过 ============ ====================

如您所见,你好是因为带有 app2 的记录器没有被禁用。

结论

基本上,您可以这样做,但只需将不需要的记录器名称添加到 conftest.py 中,如下所示:

import logging

disable_loggers = ['matplotlib','chardet.charsetprober',<add more yourself>]

def pytest_configure():
    for logger_name in disable_loggers:
        logger = logging.getLogger(logger_name)
        logger.disabled = True
,

除了能够调整日志记录级别或根本不显示任何日志输出(我确信you've read in the docs)之外,我想到的唯一方法是总体配置您的日志记录。

假设所有这些包都使用标准库日志记录工具,您可以通过各种选项来配置所记录的内容。请查看 advanced tutorial 以全面了解您的选择。

如果您不想在一般情况下为应用程序配置日志记录,而只是在测试期间,您可以使用 pytest_configurepytest_sessionstart 钩子来实现,这些钩子可以放在 {{1} } 在测试文件层次结构的根。

然后我看到三个选项:

  1. 蛮力方法是使用 conftest.pyfileConfig 的默认行为来禁用所有现有记录器。在您的dictConfig中:

    conftest.py
  2. 更微妙的方法是更改​​单个记录器的级别或禁用它们。举个例子:

    import logging.config
    
    
    def pytest_sessionstart():
        # This is the default so an empty dictionary should work,too.
        logging.config.dictConfig({'disable_existing_loggers': True})
    
  3. 最后,您可以使用 pytest_addoption 钩子添加一个类似于您提到的命令行选项。同样,在测试层次结构的根部,将以下内容放入 import logging.config def pytest_sessionstart(): logging.config.dictConfig({ 'disable_existing_loggers': False,'loggers': { # Add any noisy loggers here with a higher loglevel. 'matplotlib': {'level': 'ERROR'} } })

    conftest.py

    然后您可以通过以下方式调用 pytest:

    def pytest_addoption(parser):
        parser.addoption(
            "--logging-filter",help="Provide a comma-separated list of logger names that will be "
            "disabled."
        )
    
    
    def pytest_sessionstart(pytestconfig):
        for logger_name in pytestconfig.getoption("--logging-filter").split(","):
            # Use `logger_name.trim()[1:]` if you want the `-name` CLI syntax.
            logger = logging.getLogger(logger_name.trim())
            logger.disabled = True
    

pytest 的默认方法是隐藏所有日志,但提供 pytest --logging-filter matplotlib,chardet,... 固定装置来检查测试用例中的日志输出。如果您正在寻找特定的日志行,这将非常强大。所以问题也是为什么您需要在测试套件中查看这些日志?

,

将日志过滤器添加到 conftest.py 看起来可能很有用,我将在将来的某个时候回到这一点。不过现在,我们只是让应用程序中的日志静音。我们在应用运行的任何时候都看不到它们,而不仅仅是在测试期间。

# Hide verbose third-party logs
for log_name in ('matplotlib','fiona.env','fiona._env','PIL','chardet.charsetprober'):
    other_log = logging.getLogger(log_name)
    other_log.setLevel(logging.WARNING)