From 0998ba83319423e1c22e52f6e7147c627f87b2a6 Mon Sep 17 00:00:00 2001
From: Jim Fulton <jim@zope.com>
Date: Tue, 28 Sep 2010 20:19:23 +0000
Subject: [PATCH] Bug Fixed

- Logrotation/repoening via a SIGUSR2 signal wasn't implemented.
  (https://bugs.launchpad.net/zodb/+bug/143600)
---
 src/CHANGES.txt          |  3 ++
 src/ZEO/runzeo.py        | 28 +++++++++++++++---
 src/ZEO/tests/testZEO.py | 61 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 7cb5ddfe..36deba30 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -15,6 +15,9 @@ Bugs Fixed
   Python 2.7 wasn't officially supported, but we were releasing
   binaries for it, so ...
 
+- Logrotation/repoening via a SIGUSR2 signal wasn't implemented.
+  (https://bugs.launchpad.net/zodb/+bug/143600)
+
 3.9.6 (2010-09-21)
 ==================
 
diff --git a/src/ZEO/runzeo.py b/src/ZEO/runzeo.py
index ddfb49e3..98e67744 100644
--- a/src/ZEO/runzeo.py
+++ b/src/ZEO/runzeo.py
@@ -269,10 +269,30 @@ class ZEOServer:
         sys.exit(1)
 
     def handle_sigusr2(self):
-        # TODO: this used to reinitialize zLOG. How do I achieve
-        # the same effect with Python's logging package?
-        # Should we restart as with SIGHUP?
-        log("received SIGUSR2, but it was not handled!", level=logging.WARNING)
+        # log rotation signal - do the same as Zope 2.7/2.8...
+        if self.options.config_logger is None or os.name not in ("posix", "nt"):
+            log("received SIGUSR2, but it was not handled!", 
+                level=logging.WARNING)
+            return
+
+        loggers = [self.options.config_logger]
+
+        if os.name == "posix":
+            for l in loggers:
+                l.reopen()
+            log("Log files reopened successfully", level=logging.INFO)
+        else: # nt - same rotation code as in Zope's Signals/Signals.py
+            for l in loggers:
+                for f in l.handler_factories:
+                    handler = f()
+                    if hasattr(handler, 'rotate') and callable(handler.rotate):
+                        handler.rotate()
+            log("Log files rotation complete", level=logging.INFO)
+
+
+
+
+
 
     def close_storages(self):
         for name, storage in self.storages.items():
diff --git a/src/ZEO/tests/testZEO.py b/src/ZEO/tests/testZEO.py
index ac93bed2..82807d71 100644
--- a/src/ZEO/tests/testZEO.py
+++ b/src/ZEO/tests/testZEO.py
@@ -1299,6 +1299,67 @@ But, if we abort, we'll get up to date data and we'll see the changes.
 
     """
 
+script_template = """
+import sys
+sys.path[:] = %(path)r
+
+%(src)s
+
+"""
+
+def generate_script(name, src):
+    open(name, 'w').write(script_template % dict(
+        exe=sys.executable,
+        path=sys.path,
+        src=src,
+        ))
+
+def runzeo_logrotate_on_sigusr2():
+    """
+    >>> port = get_port()
+    >>> open('c', 'w').write('''
+    ... <zeo>
+    ...    address %s
+    ... </zeo>
+    ... <mappingstorage>
+    ... </mappingstorage>
+    ... <eventlog>
+    ...    <logfile>
+    ...       path l
+    ...    </logfile>
+    ... </eventlog>
+    ... ''' % port)
+    >>> generate_script('s', '''
+    ... import ZEO.runzeo
+    ... ZEO.runzeo.main()
+    ... ''')
+    >>> import subprocess, signal
+    >>> p = subprocess.Popen([sys.executable, 's', '-Cc'], close_fds=True)
+    >>> forker.wait_until('started',
+    ...   lambda : os.path.exists('l') and ('listening on' in open('l').read())
+    ...   )
+
+    >>> oldlog = open('l').read()
+    >>> os.rename('l', 'o')
+    >>> os.kill(p.pid, signal.SIGUSR2)
+
+    >>> forker.wait_until('new file', lambda : os.path.exists('l'))
+    >>> s = ClientStorage(('', port))
+    >>> s.close()
+    >>> forker.wait_until('See logging',
+    ...                   lambda : ('Log files ' in open('l').read()))
+    >>> open('o').read() == oldlog # No new data in old log
+    True
+
+    # Cleanup:
+
+    >>> os.kill(p.pid, signal.SIGKILL)
+    >>> _ = p.wait()
+    """
+
+if sys.platform.startswith('win'):
+    del runzeo_logrotate_on_sigusr2
+
 def quick_close_doesnt_kill_server():
     r"""
 
-- 
2.30.9