[Checkins] SVN: zc.zkzopeserver/trunk/ - Added logging-configuration support.
Jim Fulton
jim at zope.com
Thu Feb 2 22:50:05 UTC 2012
Log message for revision 124288:
- Added logging-configuration support.
- Fixed: servers were registered with the host information returned by
socket.getsockname(), which was unhelpful.
- Fixed: Killing a server (with SIGTERM) didn't shut down the
ZooKeeper connection cleanly, causing a delay in removing registered
ephemeral nodes.
Changed:
U zc.zkzopeserver/trunk/buildout.cfg
U zc.zkzopeserver/trunk/src/zc/zkzopeserver/README.txt
U zc.zkzopeserver/trunk/src/zc/zkzopeserver/__init__.py
U zc.zkzopeserver/trunk/src/zc/zkzopeserver/tests.py
-=-
Modified: zc.zkzopeserver/trunk/buildout.cfg
===================================================================
--- zc.zkzopeserver/trunk/buildout.cfg 2012-02-02 14:58:36 UTC (rev 124287)
+++ zc.zkzopeserver/trunk/buildout.cfg 2012-02-02 22:50:04 UTC (rev 124288)
@@ -1,6 +1,6 @@
[buildout]
develop = .
-parts = test py paste.ini
+parts = py server
[test]
recipe = zc.recipe.testrunner
@@ -11,6 +11,7 @@
eggs = ${test:eggs}
PasteScript
bobo
+ zc.zk
interpreter = py
@@ -25,4 +26,8 @@
use = egg:zc.zkzopeserver
zookeeper = 127.0.0.1:2181
path = /
- monitor_server = true
+ monitor_server = 127.0.0.1:0
+
+[server]
+recipe = zc.zdaemonrecipe
+program = ${buildout:bin-directory}/paster serve --log-file=- ${paste.ini:location}
Modified: zc.zkzopeserver/trunk/src/zc/zkzopeserver/README.txt
===================================================================
--- zc.zkzopeserver/trunk/src/zc/zkzopeserver/README.txt 2012-02-02 14:58:36 UTC (rev 124287)
+++ zc.zkzopeserver/trunk/src/zc/zkzopeserver/README.txt 2012-02-02 22:50:04 UTC (rev 124288)
@@ -48,6 +48,24 @@
The value is an address of the form HOST:PORT. See `Monitor
server`_ below. (Host can be empty to listen on all interfaces.)
+loggers
+ Logging configuration.
+
+ This can be one of:
+
+ - A logging level name (CRITICAL, ERROR, WARNING, INFO, or DEBUG),
+ or
+
+ - A ZConfig loggers-definition string.
+
+ If the configuration includes format strings, you'll need to use
+ double dollar signs rather than %, as in::
+
+ format $$(message)s
+
+ This is necessary due to the use of string formats in the Paste
+ Deployment configuration syntax.
+
.. test
>>> import ConfigParser, StringIO
@@ -55,6 +73,10 @@
>>> parser.readfp(StringIO.StringIO(server_config))
>>> kw = dict(parser.items('server:main'))
+ >>> import zope.testing.loggingsupport
+ >>> loghandler = zope.testing.loggingsupport.InstalledHandler(
+ ... 'zc.zkzopeserver')
+
>>> import pkg_resources
>>> dist = kw.pop('use').split(':')[1]
>>> [run] = [v.load()
@@ -84,6 +106,36 @@
>>> zk.get_children('/fooservice/providers')
[]
+ A SIGTERM signal handler is installed:
+
+ >>> import signal
+ >>> [sig, handler] = signal.signal.call_args[0]
+ >>> sig == signal.SIGTERM
+ True
+ >>> try: handler(sig, None)
+ ... except SystemExit, v: print v
+ 0
+
+ >>> signal.getsignal.return_value = handler
+ >>> signal.signal.reset_mock()
+
+ The fact that a handler was installed is logged, as is the address:
+
+ >>> print loghandler
+ zc.zkzopeserver INFO
+ Installed SIGTERM handler
+ zc.zkzopeserver INFO
+ Serving on :35177
+
+ >>> loghandler.clear()
+
+ Nothing was done w logging:
+
+ >>> import logging
+ >>> logging.basicConfig.call_args
+ >>> import ZConfig
+ >>> ZConfig.configureLoggers.call_args
+
Monitor server
==============
@@ -152,6 +204,15 @@
>>> handler.uninstall()
+ The signal handler wasn't set again, as it was already set:
+
+ >>> signal.signal.call_args
+ >>> print loghandler
+ zc.zkzopeserver INFO
+ Serving on :46834
+
+ >>> loghandler.uninstall()
+
Some notes on the monitor server:
- A monitor server won't be useful unless you've registered some
@@ -220,12 +281,18 @@
Change History
==============
-0.2.1 (2012-02-??)
+0.3.0 (2012-02-??)
------------------
+- Added logging-configuration support.
+
- Fixed: servers were registered with the host information returned by
socket.getsockname(), which was unhelpful.
+- Fixed: Killing a server (with SIGTERM) didn't shut down the
+ ZooKeeper connection cleanly, causing a delay in removing registered
+ ephemeral nodes.
+
0.2.0 (2012-01-18)
------------------
Modified: zc.zkzopeserver/trunk/src/zc/zkzopeserver/__init__.py
===================================================================
--- zc.zkzopeserver/trunk/src/zc/zkzopeserver/__init__.py 2012-02-02 14:58:36 UTC (rev 124287)
+++ zc.zkzopeserver/trunk/src/zc/zkzopeserver/__init__.py 2012-02-02 22:50:04 UTC (rev 124288)
@@ -12,12 +12,17 @@
#
##############################################################################
import asyncore
+import logging
import re
+import signal
+import sys
import threading
import zc.zk
import zope.server.dualmodechannel
import zope.server.taskthreads
+logger = logging.getLogger(__name__)
+
event_for_testing = threading.Event()
server_for_testing = None
@@ -45,10 +50,18 @@
zookeeper, path, session_timeout=None,
name=__name__, host='', port=0, threads=1, monitor_server=None,
zservertracelog=None,
+ loggers=None,
):
port = int(port)
threads = int(threads)
+ if loggers:
+ if re.match('\w+$', loggers) and hasattr(logging, loggers):
+ logging.basicConfig(level=getattr(logging, loggers))
+ else:
+ import ZConfig
+ ZConfig.configureLoggers(loggers.replace('$$(', '%('))
+
task_dispatcher = zope.server.taskthreads.ThreadedTaskDispatcher()
task_dispatcher.setThreadCount(threads)
if zservertracelog == 'true':
@@ -67,8 +80,8 @@
server.ZooKeeper = zc.zk.ZooKeeper(
zookeeper, session_timeout and int(session_timeout))
- server.ZooKeeper.register_server(
- path, "%s:%s" % (host, server.socket.getsockname()[1]), **props)
+ addr = "%s:%s" % (host, server.socket.getsockname()[1])
+ server.ZooKeeper.register_server(path, addr, **props)
map = asyncore.socket_map
poll_fun = asyncore.poll
@@ -77,7 +90,12 @@
server_for_testing = server
event_for_testing.set()
+ if not signal.getsignal(signal.SIGTERM):
+ signal.signal(signal.SIGTERM, lambda *a: sys.exit(0))
+ logger.info('Installed SIGTERM handler')
+
try:
+ logger.info('Serving on %s', addr)
while server.accepting:
poll_fun(30.0, map)
finally:
Modified: zc.zkzopeserver/trunk/src/zc/zkzopeserver/tests.py
===================================================================
--- zc.zkzopeserver/trunk/src/zc/zkzopeserver/tests.py 2012-02-02 14:58:36 UTC (rev 124287)
+++ zc.zkzopeserver/trunk/src/zc/zkzopeserver/tests.py 2012-02-02 22:50:04 UTC (rev 124288)
@@ -59,6 +59,7 @@
... host='localhost',
... port='3042',
... threads='3',
+ ... loggers='INFO',
... )
>>> import zc.zkzopeserver
@@ -92,6 +93,11 @@
>>> reset()
3
+ basicConfig was called:
+
+ >>> import logging
+ >>> logging.basicConfig.assert_called_with(level=logging.INFO)
+
Did session_timeout get passed? If we're using the mock ZooKeeper,
we camn tell:
@@ -108,6 +114,29 @@
>>> zk.close()
"""
+def test_ZConfig_logger_config():
+ """
+ Make sure various advertized options work:
+
+ >>> @zc.thread.Thread
+ ... def server():
+ ... zc.zkzopeserver.run(
+ ... slow_app, {},
+ ... zookeeper='zookeeper.example.com:2181',
+ ... path='/fooservice/providers',
+ ... loggers='This is not real $$(message)s $$(whatever)s',
+ ... )
+
+ >>> import zc.zkzopeserver
+ >>> zc.zkzopeserver.event_for_testing.wait(1)
+
+ >>> import ZConfig
+ >>> ZConfig.configureLoggers.assert_called_with(
+ ... 'This is not real %(message)s %(whatever)s')
+
+ >>> zc.zkzopeserver.stop_for_testing(server)
+ """
+
def test_monitor_server_w_empty_host():
r"""
@@ -131,9 +160,9 @@
>>> zc.zkzopeserver.stop_for_testing(server)
>>> zk.close()
- """
+ """ # '
-def readmesetup(test):
+def setup(test):
zc.zk.testing.setUp(test)
setupstack.context_manager(
test, mock.patch('netifaces.interfaces')).return_value = 'iface'
@@ -141,13 +170,23 @@
test, mock.patch('netifaces.ifaddresses')
).return_value = {2: [dict(addr='1.2.3.4')]}
-def readmeteardown(test):
+ setupstack.context_manager(
+ test, mock.patch('signal.getsignal')
+ ).return_value = 0
+ setupstack.context_manager(test, mock.patch('signal.signal'))
+
+ setupstack.context_manager(test, mock.patch('logging.basicConfig'))
+
+ setupstack.context_manager(test, mock.patch('ZConfig.configureLoggers'))
+
+def teardown(test):
setupstack.tearDown(test)
zc.zk.testing.tearDown(test)
def test_suite():
checker = zope.testing.renormalizing.RENormalizing([
(re.compile('pid = \d+'), 'pid = 9999'),
+ (re.compile('Serving on :\d+'), 'Serving on :9999'),
(re.compile(r' \d+ \d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d+'),
' IIIII DDDD-MM-DD HH:MM:SS.SS'),
])
@@ -155,11 +194,8 @@
manuel.testing.TestSuite(
manuel.doctest.Manuel(checker=checker) + manuel.capture.Manuel(),
'README.txt',
- setUp=readmesetup, tearDown=readmeteardown,
+ setUp=setup, tearDown=teardown,
),
- doctest.DocTestSuite(
- setUp=zc.zk.testing.setUp, tearDown=zc.zk.testing.tearDown,
- checker=checker,
- ),
+ doctest.DocTestSuite(setUp=setup, tearDown=teardown, checker=checker),
))
return suite
More information about the checkins
mailing list