paut
paut

Reputation: 95

Logging with pytest.ini. How to append to the file?

I am trying to add logging to my pytest tests and everything is going fine except the fact, that every other testrun's log re-writes all the precious information.

Here is my pytest.ini file:

log_file = my.log
log_file_level = DEBUG
log_file_format = %(levelname)s %(asctime)s - %(message)s (%(filename)s:%(lineno)s)
log_file_date_format=%Y-%m-%d %H:%M:%S

Here is my test code:

import os
class TestLog:
    def test_log_1(self):
        logging.info('everything is okay')
        output = 2
        assert output == 2, 'everything is okay'

    def test_log_2(self):
        output = 0
        logging.info(f'test params: {output}')
        try:
            assert output == 2, 'everything is okay'
        except AssertionError:
            logging.error(f"'everything is not okay'")
            raise AssertionError

I tried to add logging.basicConfig(filemode = "a") but it was no help.

Any help would be appreciated

Upvotes: 4

Views: 1847

Answers (1)

hoefling
hoefling

Reputation: 66531

Quoting pytest docs:

This log file is opened in write mode which means that it will be overwritten at each run tests session.

This means you can't enforce append mode via configuration; logging.basicConfig will also not help here since either it's a noop when called too late, or it does indeed configure logging, but later pytest will still ignore it and set its own handlers.

The only option I see is to manage the appending yourself by merging the new log with the previous one. Make a backup of my.log at start, merge it with new my.log before exit. Put the code in a file conftest.py in the project or tests root dir:

import io
import pathlib
import os
import shutil


def pytest_configure(config):
    log_file = config.rootpath / config.getini("log_file")
    if log_file.is_file():
        config._backup = log_file.with_name(".log.bak")
        shutil.copy(log_file, config._backup)


@pytest.hookimpl(trylast=True)
def pytest_unconfigure(config):
    log_file = config.rootpath / config.getini("log_file")
    if log_file.is_file():
        log_backup = getattr(config, "_backup", None)
        if log_backup and log_backup.is_file():
            log_file.write_text(log_backup.read_text() + log_file.read_text())
            log_backup.unlink()

Another option could be messing up pytest internals, but since the mode is hardcoded, the implementation would be rather ugly, e.g. monkeypatching the _pytest.logging._FileHandler and enforcing the append mode. I would thus advise against doing that.

Upvotes: 2

Related Questions