Skip to content

Multiple TimedRotatingFileHandler with similar names but different backup counts do not work #93205

Closed
@ilCatania

Description

@ilCatania

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

stdlibPython modules in the Lib dirtype-bugAn unexpected behavior, bug, or error

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions