Change pytest's live log level during runtime

I'm using pytest's Live Logs feature to see the logging records as they're generated. I'm currently setting the log level in the pytest.ini file, as per the docs, using the log_cli_level entry. However, it would be fairly practical to be able to change the log level from the code.

After some inspection of the pytest code, I can see it sets the self.log_cli_level field in the LoggingPlugin class. This plugin is registered with the pluginmanager here, with the key "logging-plugin".

I guess it would be a matter of accessing the plugin using the getplugin method of the PytestPluginManager to obtain the LoggingPlugin, but I'm afraid I have not found a way of accessing that manager.

Upvotes: 3

Views: 1048

Answers (1)

hoefling
hoefling

Reputation: 66171

I'm afraid I have not found a way of accessing that manager.

Use the request fixture to access the plugin manager in tests:

def test_spam(request):
    mgr = request.session.config.pluginmanager
    logging_plugin = mgr.get_plugin("logging-plugin")

However, this won't be necessary for changing the live log level (and IIRC changing LoggingPlugin.log_cli_level will only have an effect in runtest hooks, not in the test cases or fixtures). The log capturing and live logging share the same log level, so simply use the caplog fixture. Here's a simple example:

import logging
import pytest


logger = logging.getLogger(__name__)


def emit_logs():
    logger.info('sample info')
    logger.warning('sample warning')
    logger.error('sample error')
    logger.critical('sample critical')


def test_spam():
    emit_logs()

will yield

-------------------------------- live log call --------------------------------
2020-12-11 16:27:41 [    INFO] sample info (test_spam.py:9)
2020-12-11 16:27:41 [ WARNING] sample warning (test_spam.py:10)
2020-12-11 16:27:41 [   ERROR] sample error (test_spam.py:11)
2020-12-11 16:27:41 [CRITICAL] sample critical (test_spam.py:12)

Now e.g. raising the level to CRITICAL:

def test_spam(caplog):
    caplog.set_level(logging.CRITICAL)
    emit_logs()

yields only

-------------------------------- live log call --------------------------------
2020-12-11 16:27:41 [CRITICAL] sample critical (test_spam.py:12)

Using caplog as context manager:

def test_spam(caplog):
    with caplog.at_level(logging.ERROR):
        emit_logs()

will yield

-------------------------------- live log call --------------------------------
2020-12-11 16:27:41 [   ERROR] sample error (test_spam.py:11)
2020-12-11 16:27:41 [CRITICAL] sample critical (test_spam.py:12)

Dynamic changing live log level also works,

def test_eggs(caplog):
    with caplog.at_level(logging.WARNING):
        logger.info("i am not logged")
    logger.info("but i am")

as well as moving live log level switch to fixtures:

@pytest.fixture
def errors_only(caplog):
    with caplog.at_level(logging.ERROR):
        yield


@pytest.mark.usefixtures("errors_only")
def test_bacon():
    logger.error("i am printed")
    logger.info("but i am not")

Upvotes: 4

Related Questions