[Python-checkins] cpython: Closed #9556: Allowed specifying a time-of-day for a TimedRotatingFileHandler

vinay.sajip python-checkins at python.org
Fri Apr 12 18:04:36 CEST 2013


http://hg.python.org/cpython/rev/eead4be1bdd9
changeset:   83271:eead4be1bdd9
user:        Vinay Sajip <vinay_sajip at yahoo.co.uk>
date:        Fri Apr 12 17:04:23 2013 +0100
summary:
  Closed #9556: Allowed specifying a time-of-day for a TimedRotatingFileHandler to rotate.

files:
  Doc/library/logging.handlers.rst |   8 +++-
  Lib/logging/handlers.py          |  28 ++++++++++---
  Lib/test/test_logging.py         |  42 ++++++++++++++++++++
  Misc/NEWS                        |   3 +
  4 files changed, 73 insertions(+), 8 deletions(-)


diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst
--- a/Doc/library/logging.handlers.rst
+++ b/Doc/library/logging.handlers.rst
@@ -296,7 +296,7 @@
 timed intervals.
 
 
-.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False)
+.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None)
 
    Returns a new instance of the :class:`TimedRotatingFileHandler` class. The
    specified file is opened and used as the stream for logging. On rotating it also
@@ -346,6 +346,12 @@
    If *delay* is true, then file opening is deferred until the first call to
    :meth:`emit`.
 
+   If *atTime* is not ``None``, it must be a ``datetime.time`` instance which
+   specifies the time of day when rollover occurs, for the cases where rollover
+   is set to happen "at midnight" or "on a particular weekday".
+
+   .. versionchanged:: 3.4
+      *atTime* parameter was added.
 
    .. method:: doRollover()
 
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1,4 +1,4 @@
-# Copyright 2001-2012 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2013 by Vinay Sajip. All Rights Reserved.
 #
 # Permission to use, copy, modify, and distribute this software and its
 # documentation for any purpose and without fee is hereby granted,
@@ -18,7 +18,7 @@
 Additional handlers for the logging package for Python. The core package is
 based on PEP 282 and comments thereto in comp.lang.python.
 
-Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2013 Vinay Sajip. All Rights Reserved.
 
 To use, simply 'import logging.handlers' and log away!
 """
@@ -196,11 +196,12 @@
     If backupCount is > 0, when rollover is done, no more than backupCount
     files are kept - the oldest ones are deleted.
     """
-    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False):
+    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None):
         BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
         self.when = when.upper()
         self.backupCount = backupCount
         self.utc = utc
+        self.atTime = atTime
         # Calculate the real rollover interval, which is just the number of
         # seconds between rollovers.  Also set the filename suffix used when
         # a rollover occurs.  Current 'when' events supported:
@@ -270,9 +271,22 @@
             currentHour = t[3]
             currentMinute = t[4]
             currentSecond = t[5]
-            # r is the number of seconds left between now and midnight
-            r = _MIDNIGHT - ((currentHour * 60 + currentMinute) * 60 +
-                    currentSecond)
+            currentDay = t[6]
+            # r is the number of seconds left between now and the next rotation
+            if self.atTime is None:
+                rotate_ts = _MIDNIGHT
+            else:
+                rotate_ts = ((self.atTime.hour * 60 + self.atTime.minute)*60 +
+                    self.atTime.second)
+
+            r = rotate_ts - ((currentHour * 60 + currentMinute) * 60 +
+                currentSecond)
+            if r < 0:
+                # Rotate time is before the current time (for example when
+                # self.rotateAt is 13:45 and it now 14:15), rotation is
+                # tomorrow.
+                r += _MIDNIGHT
+                currentDay = (currentDay + 1) % 7
             result = currentTime + r
             # If we are rolling over on a certain day, add in the number of days until
             # the next rollover, but offset by 1 since we just calculated the time
@@ -290,7 +304,7 @@
             # This is because the above time calculation takes us to midnight on this
             # day, i.e. the start of the next day.
             if self.when.startswith('W'):
-                day = t[6] # 0 is Monday
+                day = currentDay # 0 is Monday
                 if day != self.dayOfWeek:
                     if day < self.dayOfWeek:
                         daysToWait = self.dayOfWeek - day
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -3949,6 +3949,48 @@
         assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
                      self.fn, 'W7', delay=True)
 
+    def test_compute_rollover_daily_attime(self):
+        currentTime = 0
+        atTime = datetime.time(12, 0, 0)
+        rh = logging.handlers.TimedRotatingFileHandler(
+            self.fn, when='MIDNIGHT', interval=1, backupCount=0, utc=True,
+            atTime=atTime)
+
+        actual = rh.computeRollover(currentTime)
+        self.assertEqual(actual, currentTime + 12 * 60 * 60)
+
+        actual = rh.computeRollover(currentTime + 13 * 60 * 60)
+        self.assertEqual(actual, currentTime + 36 * 60 * 60)
+
+        rh.close()
+
+    def test_compute_rollover_weekly_attime(self):
+        currentTime = 0
+        atTime = datetime.time(12, 0, 0)
+
+        wday = datetime.datetime.fromtimestamp(currentTime).weekday()
+        for day in range(7):
+            rh = logging.handlers.TimedRotatingFileHandler(
+                self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True,
+                atTime=atTime)
+
+            if wday > day:
+                expected = (7 - wday + day)
+            else:
+                expected = (day - wday)
+            expected *= 24 * 60 * 60
+            expected += 12 * 60 * 60
+            actual = rh.computeRollover(currentTime)
+            self.assertEqual(actual, expected)
+            if day == wday:
+                # goes into following week
+                expected += 7 * 24 * 60 * 60
+            actual = rh.computeRollover(currentTime + 13 * 60 * 60)
+            self.assertEqual(actual, expected)
+
+            rh.close()
+
+
 def secs(**kw):
     return datetime.timedelta(**kw) // datetime.timedelta(seconds=1)
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -34,6 +34,9 @@
 Library
 -------
 
+- Issue #9556: Allowed specifying a time-of-day for a TimedRotatingFileHandler
+  to rotate.
+
 - Issue #14971: unittest test discovery no longer gets confused when a function
   has a different __name__ than its name in the TestCase class dictionary.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list