Skip to content

Commit 8de3577

Browse files
committed
bpo-46063: Improve algorithm for computing which rolled-over log files to delete.
1 parent a62be77 commit 8de3577

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

Lib/logging/handlers.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,21 @@ def getFilesToDelete(self):
366366
fileNames = os.listdir(dirName)
367367
result = []
368368
# See bpo-44753: Don't use the extension when computing the prefix.
369-
prefix = os.path.splitext(baseName)[0] + "."
369+
n, e = os.path.splitext(baseName)
370+
prefix = n + '.'
370371
plen = len(prefix)
371372
for fileName in fileNames:
373+
if self.namer is None:
374+
# Our files will always start with baseName
375+
if not fileName.startswith(baseName):
376+
continue
377+
else:
378+
# Our files could be just about anything after custom naming, but
379+
# likely candidates are of the form
380+
# foo.log.DATETIME_SUFFIX or foo.DATETIME_SUFFIX.log
381+
if not fileName.startswith(baseName) and fileName.endswith(e) and len(fileName) > (plen + 1) and not fileName[plen+1].isdigit():
382+
continue
383+
372384
if fileName[:plen] == prefix:
373385
suffix = fileName[plen:]
374386
# See bpo-45628: The date/time suffix could be anywhere in the

Lib/test/test_logging.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import queue
3737
import random
3838
import re
39+
import shutil
3940
import socket
4041
import struct
4142
import sys
@@ -5434,6 +5435,53 @@ def test_compute_rollover_weekly_attime(self):
54345435
finally:
54355436
rh.close()
54365437

5438+
def test_compute_files_to_delete(self):
5439+
# See bpo-46063 for background
5440+
wd = tempfile.mkdtemp(prefix='test_logging_')
5441+
self.addCleanup(shutil.rmtree, wd)
5442+
times = []
5443+
dt = datetime.datetime.now()
5444+
for i in range(10):
5445+
times.append(dt.strftime('%Y-%m-%d_%H-%M-%S'))
5446+
dt += datetime.timedelta(seconds=5)
5447+
prefixes = ('a.b', 'a.b.c', 'd.e', 'd.e.f')
5448+
files = []
5449+
rotators = []
5450+
for prefix in prefixes:
5451+
p = os.path.join(wd, '%s.log' % prefix)
5452+
rotator = logging.handlers.TimedRotatingFileHandler(p, when='s',
5453+
interval=5,
5454+
backupCount=7)
5455+
rotators.append(rotator)
5456+
if prefix.startswith('a.b'):
5457+
for t in times:
5458+
files.append('%s.log.%s' % (prefix, t))
5459+
else:
5460+
rotator.namer = lambda name: name.replace('.log', '') + '.log'
5461+
for t in times:
5462+
files.append('%s.%s.log' % (prefix, t))
5463+
# Open empty files
5464+
for fn in files:
5465+
p = os.path.join(wd, fn)
5466+
with open(p, 'wb') as f:
5467+
pass
5468+
# Now the checks that only the correct files are offered up for deletion
5469+
for i, prefix in enumerate(prefixes):
5470+
rotator = rotators[i]
5471+
candidates = rotator.getFilesToDelete()
5472+
self.assertEqual(len(candidates), 3)
5473+
if prefix.startswith('a.b'):
5474+
p = '%s.log.' % prefix
5475+
for c in candidates:
5476+
d, fn = os.path.split(c)
5477+
self.assertTrue(fn.startswith(p))
5478+
else:
5479+
for c in candidates:
5480+
d, fn = os.path.split(c)
5481+
self.assertTrue(fn.endswith('.log'))
5482+
self.assertTrue(fn.startswith(prefix + '.') and
5483+
fn[len(prefix) + 2].isdigit())
5484+
54375485

54385486
def secs(**kw):
54395487
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)

0 commit comments

Comments
 (0)