Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pytest Caplog for Testing Logging Formatter

Tags:

python

pytest

I'm using a logging formatter to redact passwords. I want to write a test to confirm that the logging redactor is effective. In this example I simplified the code to redact "foo".

With this redactor code in the my my_logger.py module (simplified redaction of a specific word):

class RedactFoo:
    def __init__(self, base_formatter):
        self.base_formatter = base_formatter

    def format(self, record):
        msg = self.base_formatter.format(record)
        return msg.replace("foo", "<<REDACTED>>")

    def __getattr__(self, attr):
        return getattr(self.orig_formatter, attr)

Then I configure my logger and wrap the formatter for each handler:

logging.config.dictConfig(logging_config)

# Set the formatter on all handlers
for h in logging.root.handlers:
    h.setFormatter(RedactFoo(h.formatter))

def get_logger(name):
    return logging.getLogger(name)

If I run:

logger = my_logger.get_logger("Test")
logger.error(f"This message has foo.")

the logger redacts the message.

However, in Pytest test_my_logger.py:

import my_logger

def test_logging_redactor(caplog):
    logger = my_logger.get_logger("test")
    logger.error(f"This message has foo.")
    assert ""This message has <<REDACTED>>." in caplog.text

This test does not pass because the Pytest logging configuration overwrites my custom config. How can I use Pytest and the caplog fixture to perform this test?

I have seen the unittest solution here: How to test specific logging formatting in Python (using `pytest` and `unittest`), but I'm interested in doing this with Pytest.

like image 737
it's-yer-boy-chet Avatar asked Sep 03 '25 14:09

it's-yer-boy-chet


1 Answers

The caplog fixture works by injecting its own LogCaptureHandler to the logging framework configuration. That's how it is able to intercept log records and provide the events at caplog.text, caplog.records, caplog.record_tuples etc which the user can make assertions against. Note that it is capturing stdlib LogRecord instances, i.e. the log events have not been rendered yet and your custom format method has not been called.

If you want the formatted text redacted during test as well, you'll have to apply it also to the test logging configuration i.e. after the caplog fixture has been entered:

@pytest.fixture(autouse=True)
def redact_caplog_handlers(caplog):
    caplog.handler.setFormatter(RedactFoo(caplog.handler.formatter))
like image 149
wim Avatar answered Sep 05 '25 04:09

wim