Reputation: 798
In my project I'm parsing some PDF files using pdfplumber. During tests execution (pytest) I sometimes would like to see logs from my code for debugging purposes. This can be done by setting --log-cli-level=DEBUG
. However, this turns on messages from all code, also pdfplumber - which is very verbose and makes debugging difficult. Is there a way to selectively enable/disable loggers during test run?
pytest 4.6.3
python 3.7.3
Thanks for help!
Upvotes: 11
Views: 13039
Reputation: 177
This is more targeted than most answers here:
def test_foo(caplog):
caplog.set_level(logging.CRITICAL, logger="root.baz")
pass
where "root.baz" is to be replaced with the name of the logger (e.g. "uvicorn"). or if using the default one it can just be ignored:
def test_bar(caplog):
with caplog.at_level(logging.INFO):
pass
or, if you want even more fine-grained control, you can use caplog
as a context manager:
def test_bar(caplog):
# < code with normal logs
...
# >
# < code with target logging level
with caplog.at_level(logging.CRITICAL, logger="root.baz"):
pass
# >
See the full docs.
Upvotes: 0
Reputation: 621
Pytest does not support this by default, but you can add a custom option to your conftest.py
to turn off specific loggers.
import pytest
import logging
def pytest_addoption(parser):
"""Add a command line option to disable logger."""
parser.addoption(
"--log-disable", action="append", default=[], help="disable specific loggers"
)
def pytest_configure(config):
"""Disable the loggers."""
for name in config.getoption("--log-disable", default=[]):
logger = logging.getLogger(name)
logger.propagate = False
pytest
now supports --log-disable
without a custom option.
https://docs.pytest.org/en/7.4.x/how-to/logging.html
Upvotes: 10
Reputation: 1799
I has doing this on a per-test basis with this:
ddef with_logs(**loggers):
def all_loggers():
import logging_tree
def visit(node):
yield node[0]
for child in node[2]:
yield from visit(child)
return set(visit(logging_tree.nodes.tree()))
unknown_loggers = set(loggers) - all_loggers()
if unknown_loggers:
raise ValueError(f"Unknown loggers: {unknown_loggers}")
def decorate(f):
def disable(logger):
logging.getLogger(logger).setLevel(logging.INFO)
def enable(logger):
logging.getLogger(logger).setLevel(logging.DEBUG)
disabled_loggers = []
for k, v in loggers.items():
if not v:
disabled_loggers.append(k)
@functools.wraps(f)
def wrapped(*args, **kwargs):
for logger in disabled_loggers:
disable(logger)
try:
return f(*args, **kwargs)
finally:
for logger in disabled_loggers:
enable(logger)
return wrapped
return decorate
...
@with_logs(logger1=False, logger2=False)
def test_x():
Upvotes: 0
Reputation: 1859
No, pytest won't be able to do this for you as far as I know and can see. What I can think of is introducing your own environment variables and change log levels accordingly. Something like this:
import os
import logging
logger = logging.getLogger('mylogger')
if os.environ.get('mylogger_level'):
logger.setLevel(os.environ.get('mylogger_level'))
Upvotes: 2