Skip to content

Commit 8d01ea9

Browse files
serhiy-storchakamiss-islington
authored andcommitted
pythongh-90535: Fix support of interval>1 in logging.TimedRotatingFileHandler (pythonGH-116220)
Fix support of interval values > 1 in logging.TimedRotatingFileHandler for when='MIDNIGHT' and when='Wx'. (cherry picked from commit 269051d) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent d16519a commit 8d01ea9

File tree

3 files changed

+173
-35
lines changed

3 files changed

+173
-35
lines changed

Lib/logging/handlers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,10 @@ def computeRollover(self, currentTime):
334334
daysToWait = self.dayOfWeek - day
335335
else:
336336
daysToWait = 6 - day + self.dayOfWeek + 1
337-
result += daysToWait * (60 * 60 * 24)
337+
result += daysToWait * _MIDNIGHT
338+
result += self.interval - _MIDNIGHT * 7
339+
else:
340+
result += self.interval - _MIDNIGHT
338341
if not self.utc:
339342
dstNow = t[-1]
340343
dstAtRollover = time.localtime(result)[-1]

Lib/test/test_logging.py

Lines changed: 166 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6147,6 +6147,129 @@ def test(current, expected):
61476147

61486148
fh.close()
61496149

6150+
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
6151+
# March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0).
6152+
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
6153+
def test_compute_rollover_MIDNIGHT_local_interval(self):
6154+
# DST begins at 2012-3-11T02:00:00 and ends at 2012-11-4T02:00:00.
6155+
DT = datetime.datetime
6156+
def test(current, expected):
6157+
actual = fh.computeRollover(current.timestamp())
6158+
diff = actual - expected.timestamp()
6159+
if diff:
6160+
self.assertEqual(diff, 0, datetime.timedelta(seconds=diff))
6161+
6162+
fh = logging.handlers.TimedRotatingFileHandler(
6163+
self.fn, encoding="utf-8", when='MIDNIGHT', utc=False, interval=3)
6164+
6165+
test(DT(2012, 3, 8, 23, 59, 59), DT(2012, 3, 11, 0, 0))
6166+
test(DT(2012, 3, 9, 0, 0), DT(2012, 3, 12, 0, 0))
6167+
test(DT(2012, 3, 9, 1, 0), DT(2012, 3, 12, 0, 0))
6168+
test(DT(2012, 3, 10, 23, 59, 59), DT(2012, 3, 13, 0, 0))
6169+
test(DT(2012, 3, 11, 0, 0), DT(2012, 3, 14, 0, 0))
6170+
test(DT(2012, 3, 11, 1, 0), DT(2012, 3, 14, 0, 0))
6171+
6172+
test(DT(2012, 11, 1, 23, 59, 59), DT(2012, 11, 4, 0, 0))
6173+
test(DT(2012, 11, 2, 0, 0), DT(2012, 11, 5, 0, 0))
6174+
test(DT(2012, 11, 2, 1, 0), DT(2012, 11, 5, 0, 0))
6175+
test(DT(2012, 11, 3, 23, 59, 59), DT(2012, 11, 6, 0, 0))
6176+
test(DT(2012, 11, 4, 0, 0), DT(2012, 11, 7, 0, 0))
6177+
test(DT(2012, 11, 4, 1, 0), DT(2012, 11, 7, 0, 0))
6178+
6179+
fh.close()
6180+
6181+
fh = logging.handlers.TimedRotatingFileHandler(
6182+
self.fn, encoding="utf-8", when='MIDNIGHT', utc=False, interval=3,
6183+
atTime=datetime.time(12, 0, 0))
6184+
6185+
test(DT(2012, 3, 8, 11, 59, 59), DT(2012, 3, 10, 12, 0))
6186+
test(DT(2012, 3, 8, 12, 0), DT(2012, 3, 11, 12, 0))
6187+
test(DT(2012, 3, 8, 13, 0), DT(2012, 3, 11, 12, 0))
6188+
test(DT(2012, 3, 10, 11, 59, 59), DT(2012, 3, 12, 12, 0))
6189+
test(DT(2012, 3, 10, 12, 0), DT(2012, 3, 13, 12, 0))
6190+
test(DT(2012, 3, 10, 13, 0), DT(2012, 3, 13, 12, 0))
6191+
6192+
test(DT(2012, 11, 1, 11, 59, 59), DT(2012, 11, 3, 12, 0))
6193+
test(DT(2012, 11, 1, 12, 0), DT(2012, 11, 4, 12, 0))
6194+
test(DT(2012, 11, 1, 13, 0), DT(2012, 11, 4, 12, 0))
6195+
test(DT(2012, 11, 3, 11, 59, 59), DT(2012, 11, 5, 12, 0))
6196+
test(DT(2012, 11, 3, 12, 0), DT(2012, 11, 6, 12, 0))
6197+
test(DT(2012, 11, 3, 13, 0), DT(2012, 11, 6, 12, 0))
6198+
6199+
fh.close()
6200+
6201+
# Run with US-style DST rules: DST begins 2 a.m. on second Sunday in
6202+
# March (M3.2.0) and ends 2 a.m. on first Sunday in November (M11.1.0).
6203+
@support.run_with_tz('EST+05EDT,M3.2.0,M11.1.0')
6204+
def test_compute_rollover_W6_local_interval(self):
6205+
# DST begins at 2012-3-11T02:00:00 and ends at 2012-11-4T02:00:00.
6206+
DT = datetime.datetime
6207+
def test(current, expected):
6208+
actual = fh.computeRollover(current.timestamp())
6209+
diff = actual - expected.timestamp()
6210+
if diff:
6211+
self.assertEqual(diff, 0, datetime.timedelta(seconds=diff))
6212+
6213+
fh = logging.handlers.TimedRotatingFileHandler(
6214+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3)
6215+
6216+
test(DT(2012, 2, 19, 23, 59, 59), DT(2012, 3, 5, 0, 0))
6217+
test(DT(2012, 2, 20, 0, 0), DT(2012, 3, 12, 0, 0))
6218+
test(DT(2012, 2, 20, 1, 0), DT(2012, 3, 12, 0, 0))
6219+
test(DT(2012, 3, 4, 23, 59, 59), DT(2012, 3, 19, 0, 0))
6220+
test(DT(2012, 3, 5, 0, 0), DT(2012, 3, 26, 0, 0))
6221+
test(DT(2012, 3, 5, 1, 0), DT(2012, 3, 26, 0, 0))
6222+
6223+
test(DT(2012, 10, 14, 23, 59, 59), DT(2012, 10, 29, 0, 0))
6224+
test(DT(2012, 10, 15, 0, 0), DT(2012, 11, 5, 0, 0))
6225+
test(DT(2012, 10, 15, 1, 0), DT(2012, 11, 5, 0, 0))
6226+
test(DT(2012, 10, 28, 23, 59, 59), DT(2012, 11, 12, 0, 0))
6227+
test(DT(2012, 10, 29, 0, 0), DT(2012, 11, 19, 0, 0))
6228+
test(DT(2012, 10, 29, 1, 0), DT(2012, 11, 19, 0, 0))
6229+
6230+
fh.close()
6231+
6232+
fh = logging.handlers.TimedRotatingFileHandler(
6233+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3,
6234+
atTime=datetime.time(0, 0, 0))
6235+
6236+
test(DT(2012, 2, 25, 23, 59, 59), DT(2012, 3, 11, 0, 0))
6237+
test(DT(2012, 2, 26, 0, 0), DT(2012, 3, 18, 0, 0))
6238+
test(DT(2012, 2, 26, 1, 0), DT(2012, 3, 18, 0, 0))
6239+
test(DT(2012, 3, 10, 23, 59, 59), DT(2012, 3, 25, 0, 0))
6240+
test(DT(2012, 3, 11, 0, 0), DT(2012, 4, 1, 0, 0))
6241+
test(DT(2012, 3, 11, 1, 0), DT(2012, 4, 1, 0, 0))
6242+
6243+
test(DT(2012, 10, 20, 23, 59, 59), DT(2012, 11, 4, 0, 0))
6244+
test(DT(2012, 10, 21, 0, 0), DT(2012, 11, 11, 0, 0))
6245+
test(DT(2012, 10, 21, 1, 0), DT(2012, 11, 11, 0, 0))
6246+
test(DT(2012, 11, 3, 23, 59, 59), DT(2012, 11, 18, 0, 0))
6247+
test(DT(2012, 11, 4, 0, 0), DT(2012, 11, 25, 0, 0))
6248+
test(DT(2012, 11, 4, 1, 0), DT(2012, 11, 25, 0, 0))
6249+
6250+
fh.close()
6251+
6252+
fh = logging.handlers.TimedRotatingFileHandler(
6253+
self.fn, encoding="utf-8", when='W6', utc=False, interval=3,
6254+
atTime=datetime.time(12, 0, 0))
6255+
6256+
test(DT(2012, 2, 18, 11, 59, 59), DT(2012, 3, 4, 12, 0))
6257+
test(DT(2012, 2, 19, 12, 0), DT(2012, 3, 11, 12, 0))
6258+
test(DT(2012, 2, 19, 13, 0), DT(2012, 3, 11, 12, 0))
6259+
test(DT(2012, 3, 4, 11, 59, 59), DT(2012, 3, 18, 12, 0))
6260+
test(DT(2012, 3, 4, 12, 0), DT(2012, 3, 25, 12, 0))
6261+
test(DT(2012, 3, 4, 13, 0), DT(2012, 3, 25, 12, 0))
6262+
6263+
test(DT(2012, 10, 14, 11, 59, 59), DT(2012, 10, 28, 12, 0))
6264+
test(DT(2012, 10, 14, 12, 0), DT(2012, 11, 4, 12, 0))
6265+
test(DT(2012, 10, 14, 13, 0), DT(2012, 11, 4, 12, 0))
6266+
test(DT(2012, 10, 28, 11, 59, 59), DT(2012, 11, 11, 12, 0))
6267+
test(DT(2012, 10, 28, 12, 0), DT(2012, 11, 18, 12, 0))
6268+
test(DT(2012, 10, 28, 13, 0), DT(2012, 11, 18, 12, 0))
6269+
6270+
fh.close()
6271+
6272+
61506273
def secs(**kw):
61516274
return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
61526275

@@ -6158,40 +6281,49 @@ def secs(**kw):
61586281
# current time (epoch start) is a Thursday, W0 means Monday
61596282
('W0', secs(days=4, hours=24)),
61606283
):
6161-
def test_compute_rollover(self, when=when, exp=exp):
6162-
rh = logging.handlers.TimedRotatingFileHandler(
6163-
self.fn, encoding="utf-8", when=when, interval=1, backupCount=0, utc=True)
6164-
currentTime = 0.0
6165-
actual = rh.computeRollover(currentTime)
6166-
if exp != actual:
6167-
# Failures occur on some systems for MIDNIGHT and W0.
6168-
# Print detailed calculation for MIDNIGHT so we can try to see
6169-
# what's going on
6170-
if when == 'MIDNIGHT':
6171-
try:
6172-
if rh.utc:
6173-
t = time.gmtime(currentTime)
6174-
else:
6175-
t = time.localtime(currentTime)
6176-
currentHour = t[3]
6177-
currentMinute = t[4]
6178-
currentSecond = t[5]
6179-
# r is the number of seconds left between now and midnight
6180-
r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
6181-
currentMinute) * 60 +
6182-
currentSecond)
6183-
result = currentTime + r
6184-
print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
6185-
print('currentHour: %s' % currentHour, file=sys.stderr)
6186-
print('currentMinute: %s' % currentMinute, file=sys.stderr)
6187-
print('currentSecond: %s' % currentSecond, file=sys.stderr)
6188-
print('r: %s' % r, file=sys.stderr)
6189-
print('result: %s' % result, file=sys.stderr)
6190-
except Exception as e:
6191-
print('exception in diagnostic code: %s' % e, file=sys.stderr)
6192-
self.assertEqual(exp, actual)
6193-
rh.close()
6194-
setattr(TimedRotatingFileHandlerTest, "test_compute_rollover_%s" % when, test_compute_rollover)
6284+
for interval in 1, 3:
6285+
def test_compute_rollover(self, when=when, interval=interval, exp=exp):
6286+
rh = logging.handlers.TimedRotatingFileHandler(
6287+
self.fn, encoding="utf-8", when=when, interval=interval, backupCount=0, utc=True)
6288+
currentTime = 0.0
6289+
actual = rh.computeRollover(currentTime)
6290+
if when.startswith('W'):
6291+
exp += secs(days=7*(interval-1))
6292+
else:
6293+
exp *= interval
6294+
if exp != actual:
6295+
# Failures occur on some systems for MIDNIGHT and W0.
6296+
# Print detailed calculation for MIDNIGHT so we can try to see
6297+
# what's going on
6298+
if when == 'MIDNIGHT':
6299+
try:
6300+
if rh.utc:
6301+
t = time.gmtime(currentTime)
6302+
else:
6303+
t = time.localtime(currentTime)
6304+
currentHour = t[3]
6305+
currentMinute = t[4]
6306+
currentSecond = t[5]
6307+
# r is the number of seconds left between now and midnight
6308+
r = logging.handlers._MIDNIGHT - ((currentHour * 60 +
6309+
currentMinute) * 60 +
6310+
currentSecond)
6311+
result = currentTime + r
6312+
print('t: %s (%s)' % (t, rh.utc), file=sys.stderr)
6313+
print('currentHour: %s' % currentHour, file=sys.stderr)
6314+
print('currentMinute: %s' % currentMinute, file=sys.stderr)
6315+
print('currentSecond: %s' % currentSecond, file=sys.stderr)
6316+
print('r: %s' % r, file=sys.stderr)
6317+
print('result: %s' % result, file=sys.stderr)
6318+
except Exception as e:
6319+
print('exception in diagnostic code: %s' % e, file=sys.stderr)
6320+
self.assertEqual(exp, actual)
6321+
rh.close()
6322+
name = "test_compute_rollover_%s" % when
6323+
if interval > 1:
6324+
name += "_interval"
6325+
test_compute_rollover.__name__ = name
6326+
setattr(TimedRotatingFileHandlerTest, name, test_compute_rollover)
61956327

61966328

61976329
@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix support of *interval* values > 1 in
2+
:class:`logging.TimedRotatingFileHandler` for ``when='MIDNIGHT'`` and
3+
``when='Wx'``.

0 commit comments

Comments
 (0)