我正在使用 pytest-3.7.1,它对日志记录有很好的支持,包括在测试期间实时记录到标准输出。我正在使用
--log-cli-level=DEBUG
将所有调试级别日志记录转储到控制台。
我遇到的问题是
--log-cli-level=DEBUG
为我的测试程序中的所有模块(包括第三方依赖项)打开调试日志记录,并且它会用大量无趣的输出淹没日志。
Python 的日志记录模块能够设置每个模块的日志记录级别。这可以实现选择性日志记录 - 例如,在普通的 Python 程序中,我可以仅对我自己的一两个模块打开调试,并将日志输出限制为这些模块,或者为每个模块设置不同的日志级别。这可以关闭嘈杂库的调试级别日志记录。
所以我想做的是将相同的概念应用于 pytest 的日志记录 - 即从命令行为特定的非根记录器指定日志记录级别。例如,如果我有一个名为
test_foo.py
的模块,那么我正在寻找一种方法来设置该模块的日志级别 从命令行。
我准备在必要时自行推出(我知道如何向 pytest 添加自定义参数),但在此之前我只想确保还没有解决方案。有人知道吗?
启用/禁用/修改Python中任何模块的日志级别:
logging.getLogger("module_name").setLevel(logging.log_level)
我遇到了同样的问题,并在另一个answer中找到了解决方案:
不要使用
--log-cli-level=DEBUG
,而使用 --log-level DEBUG
。它禁用所有第三方模块日志(在我的例子中,我有大量的 matplotlib 日志),但仍然为每个失败的测试输出应用程序日志。
我通过编写一个工厂类并使用它将根记录器的级别设置为
logger.INFO
并使用命令行中的日志记录级别来实现从工厂获得的所有记录器的工作。如果命令行的日志记录级别高于您在类中指定的最小全局日志级别(使用常量 MINIMUM_GLOBAL_LOG_LEVEL
),则全局日志级别不会更改。
import logging
MODULE_FIELD_WIDTH_IN_CHARS = '20'
LINE_NO_FIELD_WIDTH_IN_CHARS = '3'
LEVEL_NAME_FIELD_WIDTH_IN_CHARS = '8'
MINIMUM_GLOBAL_LOG_LEVEL = logging.INFO
class EasyLogger():
root_logger = logging.getLogger()
specified_log_level = root_logger.level
format_string = '{asctime} '
format_string += '{module:>' + MODULE_FIELD_WIDTH_IN_CHARS + 's}'
format_string += '[{lineno:' + LINE_NO_FIELD_WIDTH_IN_CHARS + 'd}]'
format_string += '[{levelname:^' + LEVEL_NAME_FIELD_WIDTH_IN_CHARS + 's}]: '
format_string += '{message}'
level_change_warning_sent = False
@classmethod
def get_logger(cls, logger_name):
if not EasyLogger._logger_has_format(cls.root_logger, cls.format_string):
EasyLogger._setup_root_logger()
logger = logging.getLogger(logger_name)
logger.setLevel(cls.specified_log_level)
return logger
@classmethod
def _setup_root_logger(cls):
formatter = logging.Formatter(fmt=cls.format_string, style='{')
if not cls.root_logger.hasHandlers():
handler = logging.StreamHandler()
cls.root_logger.addHandler(handler)
for handler in cls.root_logger.handlers:
handler.setFormatter(formatter)
cls.root_logger.setLevel(MINIMUM_GLOBAL_LOG_LEVEL)
if (cls.specified_log_level < MINIMUM_GLOBAL_LOG_LEVEL and
cls.level_change_warning_sent is False):
cls.root_logger.log(
max(cls.specified_log_level, logging.WARNING),
"Setting log level for %s class to %s, all others to %s" % (
__name__,
cls.specified_log_level,
MINIMUM_GLOBAL_LOG_LEVEL
)
)
cls.level_change_warning_sent = True
@staticmethod
def _logger_has_format(logger, format_string):
for handler in logger.handlers:
return handler.format == format_string
return False
然后使用上面的类正常发送日志,就像使用
logging.logger
对象一样,如下所示:
from EasyLogger import EasyLogger
class MySuperAwesomeClass():
def __init__(self):
self.logger = EasyLogger.get_logger(__name__)
def foo(self):
self.logger.debug("debug message")
self.logger.info("info message")
self.logger.warning("warning message")
self.logger.critical("critical message")
self.logger.error("error message")
我遇到了同样的问题,并通过在
conftest.py
中设置日志级别解决了它。由于日志记录模块是单例,因此这将对整个 pytest 运行产生全局影响。
在conftest.py中
import logging
...
# Set sensible log levels for sub and third-party modules
logging.getLogger("module1").setLevel(logging.INFO)
logging.getLogger("some.external.module").setLevel(logging.WARNING)
...
然后您可以使用自定义 cli 参数自行修改日志级别。