mirror of https://github.com/python/cpython
gh-93205: When rotating logs with no namer specified, match whole extension (GH-93224)
This commit is contained in:
parent
347acded84
commit
113687a838
|
@ -369,16 +369,20 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
dirName, baseName = os.path.split(self.baseFilename)
|
dirName, baseName = os.path.split(self.baseFilename)
|
||||||
fileNames = os.listdir(dirName)
|
fileNames = os.listdir(dirName)
|
||||||
result = []
|
result = []
|
||||||
# See bpo-44753: Don't use the extension when computing the prefix.
|
if self.namer is None:
|
||||||
n, e = os.path.splitext(baseName)
|
prefix = baseName + '.'
|
||||||
prefix = n + '.'
|
plen = len(prefix)
|
||||||
plen = len(prefix)
|
for fileName in fileNames:
|
||||||
for fileName in fileNames:
|
if fileName[:plen] == prefix:
|
||||||
if self.namer is None:
|
suffix = fileName[plen:]
|
||||||
# Our files will always start with baseName
|
if self.extMatch.match(suffix):
|
||||||
if not fileName.startswith(baseName):
|
result.append(os.path.join(dirName, fileName))
|
||||||
continue
|
else:
|
||||||
else:
|
# See bpo-44753: Don't use the extension when computing the prefix.
|
||||||
|
n, e = os.path.splitext(baseName)
|
||||||
|
prefix = n + '.'
|
||||||
|
plen = len(prefix)
|
||||||
|
for fileName in fileNames:
|
||||||
# Our files could be just about anything after custom naming, but
|
# Our files could be just about anything after custom naming, but
|
||||||
# likely candidates are of the form
|
# likely candidates are of the form
|
||||||
# foo.log.DATETIME_SUFFIX or foo.DATETIME_SUFFIX.log
|
# foo.log.DATETIME_SUFFIX or foo.DATETIME_SUFFIX.log
|
||||||
|
@ -386,15 +390,16 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
len(fileName) > (plen + 1) and not fileName[plen+1].isdigit()):
|
len(fileName) > (plen + 1) and not fileName[plen+1].isdigit()):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if fileName[:plen] == prefix:
|
if fileName[:plen] == prefix:
|
||||||
suffix = fileName[plen:]
|
suffix = fileName[plen:]
|
||||||
# See bpo-45628: The date/time suffix could be anywhere in the
|
# See bpo-45628: The date/time suffix could be anywhere in the
|
||||||
# filename
|
# filename
|
||||||
parts = suffix.split('.')
|
|
||||||
for part in parts:
|
parts = suffix.split('.')
|
||||||
if self.extMatch.match(part):
|
for part in parts:
|
||||||
result.append(os.path.join(dirName, fileName))
|
if self.extMatch.match(part):
|
||||||
break
|
result.append(os.path.join(dirName, fileName))
|
||||||
|
break
|
||||||
if len(result) < self.backupCount:
|
if len(result) < self.backupCount:
|
||||||
result = []
|
result = []
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -6193,6 +6193,43 @@ class TimedRotatingFileHandlerTest(BaseFileTest):
|
||||||
self.assertTrue(fn.startswith(prefix + '.') and
|
self.assertTrue(fn.startswith(prefix + '.') and
|
||||||
fn[len(prefix) + 2].isdigit())
|
fn[len(prefix) + 2].isdigit())
|
||||||
|
|
||||||
|
def test_compute_files_to_delete_same_filename_different_extensions(self):
|
||||||
|
# See GH-93205 for background
|
||||||
|
wd = pathlib.Path(tempfile.mkdtemp(prefix='test_logging_'))
|
||||||
|
self.addCleanup(shutil.rmtree, wd)
|
||||||
|
times = []
|
||||||
|
dt = datetime.datetime.now()
|
||||||
|
n_files = 10
|
||||||
|
for _ in range(n_files):
|
||||||
|
times.append(dt.strftime('%Y-%m-%d_%H-%M-%S'))
|
||||||
|
dt += datetime.timedelta(seconds=5)
|
||||||
|
prefixes = ('a.log', 'a.log.b')
|
||||||
|
files = []
|
||||||
|
rotators = []
|
||||||
|
for i, prefix in enumerate(prefixes):
|
||||||
|
backupCount = i+1
|
||||||
|
rotator = logging.handlers.TimedRotatingFileHandler(wd / prefix, when='s',
|
||||||
|
interval=5,
|
||||||
|
backupCount=backupCount,
|
||||||
|
delay=True)
|
||||||
|
rotators.append(rotator)
|
||||||
|
for t in times:
|
||||||
|
files.append('%s.%s' % (prefix, t))
|
||||||
|
# Create empty files
|
||||||
|
for f in files:
|
||||||
|
(wd / f).touch()
|
||||||
|
# Now the checks that only the correct files are offered up for deletion
|
||||||
|
for i, prefix in enumerate(prefixes):
|
||||||
|
backupCount = i+1
|
||||||
|
rotator = rotators[i]
|
||||||
|
candidates = rotator.getFilesToDelete()
|
||||||
|
self.assertEqual(len(candidates), n_files - backupCount)
|
||||||
|
matcher = re.compile(r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(\.\w+)?$")
|
||||||
|
for c in candidates:
|
||||||
|
d, fn = os.path.split(c)
|
||||||
|
self.assertTrue(fn.startswith(prefix))
|
||||||
|
suffix = fn[(len(prefix)+1):]
|
||||||
|
self.assertRegex(suffix, matcher)
|
||||||
|
|
||||||
def secs(**kw):
|
def secs(**kw):
|
||||||
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
|
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fixed a bug in :class:`logging.handlers.TimedRotatingFileHandler` where multiple rotating handler instances pointing to files with the same name but different extensions would conflict and not delete the correct files.
|
Loading…
Reference in New Issue