Description
Bug report
When setting up multiple logging handlers of type TimedRotatingFileHandler
that log to the same directory and only differ by the file extension, rollover does not work properly for either of them.
Consider this configuration:
root = logging.getLogger()
root.addHandler(TimedRotatingFileHandler("test.log", when="S", backupCount=2, delay=True))
root.addHandler(TimedRotatingFileHandler("test.log.json", when="S", backupCount=1, delay=True))
running this for several seconds should cause the logging directory to have 5 files (time stamps would obviously vary based on when you run it) :
test.log
test.log.2022-05-25_05-19-19
test.log.2022-05-25_05-19-18
test.log.json
test.log.json.2022-05-25_05-19-19
However, the second handler deletes files that should only match the first handler, so it ends up not deleting its own files:
test.log
test.log.2022-05-25_05-19-19
test.log.json
test.log.json.2022-05-25_05-19-17
test.log.json.2022-05-25_05-19-18
test.log.json.2022-05-25_05-19-19
Digging through code this seems to be caused by the change in bpo-44753 aka #88916, reverting this change solves the issue for me.
Here's the full code to reproduce the issue:
import logging
import datetime
from logging.handlers import TimedRotatingFileHandler
from tempfile import TemporaryDirectory
from pathlib import Path
from time import sleep
with TemporaryDirectory() as td:
tmp_path = Path(td)
filename = "test.log"
filename_json = f"{filename}.json"
logfile = tmp_path / filename
logfile_json = tmp_path / filename_json
h1 = TimedRotatingFileHandler(logfile, when="S", backupCount=2, delay=True)
h2 = TimedRotatingFileHandler(logfile_json, when="S", backupCount=1, delay=True)
times = []
for log_str in ("hi1", "hi2", "hi3", "hi4"):
times.append(datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
for h in (h1, h2):
h.emit(logging.LogRecord("name", logging.INFO, "path", 1, log_str, (), None))
sleep(1)
assert logfile.is_file()
actual = set(f.name for f in tmp_path.iterdir())
expected = {
"test.log",
f"test.log.{times[-3]}",
f"test.log.{times[-2]}",
"test.log.json",
f"test.log.json.{times[-2]}",
}
assert actual == expected, (
f"\n\texpected:\t{','.join(expected)}" f"\n\tactual:\t\t{','.join(actual)}"
)
assert logfile.read_text() == "hi4\n"
assert logfile_json.read_text() == "hi4\n"
assert (tmp_path / f"{filename}.{times[-3]}").read_text() == "hi2\n"
assert (tmp_path / f"{filename_json}.{times[-2]}").read_text() == "hi3\n"
Your environment
Tested this with Python 3.9.7 and 3.10.4, and with the current development cpython code.
Linux 3.10.0-957.27.2.el7.x86_64 #1 SMP Mon Jul 29 17:46:05 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status