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.
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With