[Zconfig] SVN: ZConfig/trunk/ Added support for file rotation by time by specifying when and

Jim Fulton jim at zope.com
Thu Sep 4 15:21:31 EDT 2008


Log message for revision 90823:
  Added support for file rotation by time by specifying when and
  interval, rather than max-size, for log files.
  

Changed:
  U   ZConfig/trunk/NEWS.txt
  U   ZConfig/trunk/ZConfig/components/logger/handlers.py
  U   ZConfig/trunk/ZConfig/components/logger/handlers.xml
  U   ZConfig/trunk/ZConfig/components/logger/loghandler.py
  U   ZConfig/trunk/ZConfig/components/logger/tests/test_logger.py

-=-
Modified: ZConfig/trunk/NEWS.txt
===================================================================
--- ZConfig/trunk/NEWS.txt	2008-09-04 19:15:42 UTC (rev 90822)
+++ ZConfig/trunk/NEWS.txt	2008-09-04 19:21:31 UTC (rev 90823)
@@ -2,9 +2,12 @@
 Change History for ZConfig
 ==========================
 
-ZConfig 2.5.2 (unreleased)
+ZConfig 2.6.0 (2008/09/03)
 --------------------------
 
+- Added support for file rotation by time by specifying when and
+  interval, rather than max-size, for log files. 
+
 - Removed dependency on setuptools from the setup.py.
 
 

Modified: ZConfig/trunk/ZConfig/components/logger/handlers.py
===================================================================
--- ZConfig/trunk/ZConfig/components/logger/handlers.py	2008-09-04 19:15:42 UTC (rev 90822)
+++ ZConfig/trunk/ZConfig/components/logger/handlers.py	2008-09-04 19:21:31 UTC (rev 90823)
@@ -97,6 +97,8 @@
         path = self.section.path
         max_bytes = self.section.max_size
         old_files = self.section.old_files
+        when = self.section.when
+        interval = self.section.interval
         if path == "STDERR":
             if max_bytes or old_files:
                 raise ValueError("cannot rotate STDERR")
@@ -105,13 +107,23 @@
             if max_bytes or old_files:
                 raise ValueError("cannot rotate STDOUT")
             handler = loghandler.StreamHandler(sys.stdout)
-        elif max_bytes or old_files:
-            if not max_bytes:
-                raise ValueError("max-bytes must be set for log rotation")
+        elif when or max_bytes or old_files or interval:
             if not old_files:
                 raise ValueError("old-files must be set for log rotation")
-            handler = loghandler.RotatingFileHandler(
-                path, maxBytes=max_bytes, backupCount=old_files)
+            if when:
+                if max_bytes:
+                    raise ValueError("can't set *both* max_bytes and when")
+                if not interval:
+                    interval = 1
+                handler = loghandler.TimedRotatingFileHandler(
+                    path, when=when, interval=interval,
+                    backupCount=old_files)
+            elif max_bytes:
+                handler = loghandler.RotatingFileHandler(
+                    path, maxBytes=max_bytes, backupCount=old_files)
+            else:
+                raise ValueError(
+                    "max-bytes or when must be set for log rotation")
         else:
             handler = loghandler.FileHandler(path)
         return handler

Modified: ZConfig/trunk/ZConfig/components/logger/handlers.xml
===================================================================
--- ZConfig/trunk/ZConfig/components/logger/handlers.xml	2008-09-04 19:15:42 UTC (rev 90822)
+++ ZConfig/trunk/ZConfig/components/logger/handlers.xml	2008-09-04 19:21:31 UTC (rev 90823)
@@ -32,6 +32,8 @@
     <key name="path" required="yes"/>
     <key name="old-files" required="no" default="0" datatype="integer"/>
     <key name="max-size" required="no" default="0" datatype="byte-size"/>
+    <key name="when" required="no" default="" datatype="string"/>
+    <key name="interval" required="no" default="0" datatype="integer"/>
     <key name="format"
          default="------\n%(asctime)s %(levelname)s %(name)s %(message)s"
          datatype=".log_format"/>

Modified: ZConfig/trunk/ZConfig/components/logger/loghandler.py
===================================================================
--- ZConfig/trunk/ZConfig/components/logger/loghandler.py	2008-09-04 19:15:42 UTC (rev 90822)
+++ ZConfig/trunk/ZConfig/components/logger/loghandler.py	2008-09-04 19:21:31 UTC (rev 90823)
@@ -19,6 +19,8 @@
 
 from logging import Handler, StreamHandler
 from logging.handlers import RotatingFileHandler as _RotatingFileHandler
+from logging.handlers import TimedRotatingFileHandler \
+     as _TimedRotatingFileHandler
 from logging.handlers import SysLogHandler, BufferingHandler
 from logging.handlers import HTTPHandler, SMTPHandler
 from logging.handlers import NTEventLogHandler as Win32EventLogHandler
@@ -123,7 +125,21 @@
     def reopen(self):
         self.doRollover()
 
+class TimedRotatingFileHandler(_TimedRotatingFileHandler):
 
+    def __init__(self, *args, **kw):
+        _TimedRotatingFileHandler.__init__(self, *args, **kw)
+        self._wr = weakref.ref(self, _remove_from_reopenable)
+        _reopenable_handlers.append(self._wr)
+
+    def close(self):
+        _TimedRotatingFileHandler.close(self)
+        _remove_from_reopenable(self._wr)
+
+    def reopen(self):
+        self.doRollover()
+
+
 class NullHandler(Handler):
     """Handler that does nothing."""
 

Modified: ZConfig/trunk/ZConfig/components/logger/tests/test_logger.py
===================================================================
--- ZConfig/trunk/ZConfig/components/logger/tests/test_logger.py	2008-09-04 19:15:42 UTC (rev 90822)
+++ ZConfig/trunk/ZConfig/components/logger/tests/test_logger.py	2008-09-04 19:21:31 UTC (rev 90823)
@@ -188,6 +188,58 @@
         logger.removeHandler(logfile)
         logfile.close()
 
+    def test_with_timed_rotating_logfile(self):
+        fn = self.mktemp()
+        logger = self.check_simple_logger("<eventlog>\n"
+                                          "  <logfile>\n"
+                                          "    path %s\n"
+                                          "    level debug\n"
+                                          "    when D\n"
+                                          "    old-files 11\n"
+                                          "  </logfile>\n"
+                                          "</eventlog>" % fn)
+        logfile = logger.handlers[0]
+        self.assertEqual(logfile.level, logging.DEBUG)
+        self.assertEqual(logfile.backupCount, 11)
+        self.assertEqual(logfile.interval, 86400)
+        self.assert_(isinstance(logfile, loghandler.TimedRotatingFileHandler))
+        logger.removeHandler(logfile)
+        logfile.close()
+
+    def test_with_timed_rotating_logfile(self):
+        fn = self.mktemp()
+        logger = self.check_simple_logger("<eventlog>\n"
+                                          "  <logfile>\n"
+                                          "    path %s\n"
+                                          "    level debug\n"
+                                          "    when D\n"
+                                          "    interval 3\n"
+                                          "    old-files 11\n"
+                                          "  </logfile>\n"
+                                          "</eventlog>" % fn)
+        logfile = logger.handlers[0]
+        self.assertEqual(logfile.level, logging.DEBUG)
+        self.assertEqual(logfile.backupCount, 11)
+        self.assertEqual(logfile.interval, 86400*3)
+        self.assert_(isinstance(logfile, loghandler.TimedRotatingFileHandler))
+        logger.removeHandler(logfile)
+        logfile.close()
+
+    def test_with_timed_rotating_logfile_and_size_should_fail(self):
+        fn = self.mktemp()
+        self.assertRaises(
+            ValueError,
+            self.check_simple_logger, "<eventlog>\n"
+                                          "  <logfile>\n"
+                                          "    path %s\n"
+                                          "    level debug\n"
+                                          "    max-size 5mb\n"
+                                          "    when D\n"
+                                          "    old-files 10\n"
+                                          "  </logfile>\n"
+                                          "</eventlog>" % fn)
+
+
     def check_standard_stream(self, name):
         old_stream = getattr(sys, name)
         conf = self.get_config("""
@@ -444,6 +496,12 @@
           max-size 1mb
           old-files 3
         </logfile>
+        <logfile>
+          path  %(path1)s
+          level info
+          when D
+          old-files 3
+        </logfile>
       </logger>
 
       <logger>



More information about the ZConfig mailing list