[Repoze-checkins] r1129 - in repoze.accelerator/trunk/repoze/accelerator: . tests
Chris McDonough
chrism at agendaless.com
Tue Jun 24 10:15:07 EDT 2008
Author: Chris McDonough <chrism at agendaless.com>
Date: Tue Jun 24 10:15:06 2008
New Revision: 1129
Log:
Add PEP 282 logging.
Added:
repoze.accelerator/trunk/repoze/accelerator/logger.py (contents, props changed)
repoze.accelerator/trunk/repoze/accelerator/tests/test_logger.py (contents, props changed)
Modified:
repoze.accelerator/trunk/repoze/accelerator/interfaces.py
repoze.accelerator/trunk/repoze/accelerator/middleware.py
repoze.accelerator/trunk/repoze/accelerator/policy.py
repoze.accelerator/trunk/repoze/accelerator/storage.py
repoze.accelerator/trunk/repoze/accelerator/tests/test_middleware.py
repoze.accelerator/trunk/repoze/accelerator/tests/test_policy.py
repoze.accelerator/trunk/repoze/accelerator/tests/test_storage.py
Modified: repoze.accelerator/trunk/repoze/accelerator/interfaces.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/interfaces.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/interfaces.py Tue Jun 24 10:15:06 2008
@@ -1,5 +1,16 @@
from zope.interface import Interface
+class ILoggerFactory(Interface):
+ """ Required API of entry point which creates a logger.
+ """
+ def __call__(config):
+ """ Return a PEP 282 logger.
+
+ o 'config', if passed, will be a dictionary whose values may be
+ used to configure the logger. By convention, the keys which
+ are relevant to the logger start with 'logger.'.
+ """
+
class IChunkHandler(Interface):
""" API of the helper object returned from a call to 'IStorage.store'.
"""
@@ -36,8 +47,11 @@
class IPolicyFactory(Interface):
""" Required API of the entry point which creates a policy plugin.
"""
- def __call__(storage, config=None):
+ def __call__(logger, storage, config):
""" Return a new policy plugin.
+
+ o The plugin may use the services of the PEP 282 logger
+ passed in as 'logger'. This may be None.
o The new plugin should use the given 'storage' plugin as a
backing store.
@@ -75,8 +89,10 @@
class IStorageFactory(Interface):
""" Required API of the entry point which creates a storage plugin.
"""
- def __call__(config=None):
+ def __call__(logger, config):
""" Return a new storage plugin.
+
+ o 'logger' will be a PEP 282 logger instance or None.
o 'config', if passed, will be a dictionary whose values may be
used to configure the plugin. By convention, the keys which
Added: repoze.accelerator/trunk/repoze/accelerator/logger.py
==============================================================================
--- (empty file)
+++ repoze.accelerator/trunk/repoze/accelerator/logger.py Tue Jun 24 10:15:06 2008
@@ -0,0 +1,35 @@
+from zope.interface import directlyProvides
+from repoze.accelerator.interfaces import ILoggerFactory
+
+def make_logger(config):
+ import os
+ import sys
+ import logging
+
+ if os.environ.get('ACCELERATOR_LOG'):
+ log_stream = sys.stdout
+ log_level = logging.DEBUG
+
+ else:
+ log_file = config.get('logger.filename', '')
+ if not log_file or log_file.lower() == 'none':
+ return None
+ if log_file.lower() == 'stdout':
+ log_stream = sys.stdout
+ elif log_file.lower() == 'stderr':
+ log_stream = sys.stderr
+ else:
+ log_stream = open(os.path.abspath(os.path.normpath(log_file)), 'a+')
+ log_level = config.get('logger.log_level', 'INFO')
+ log_level = log_level.upper()
+ log_level = getattr(logging, log_level)
+
+ handler = logging.StreamHandler(log_stream)
+ fmt = '%(asctime)s %(message)s'
+ formatter = logging.Formatter(fmt)
+ handler.setFormatter(formatter)
+ logger = logging.Logger('repoze.accelerator')
+ logger.addHandler(handler)
+ logger.setLevel(log_level)
+ return logger
+directlyProvides(make_logger, ILoggerFactory)
Modified: repoze.accelerator/trunk/repoze/accelerator/middleware.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/middleware.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/middleware.py Tue Jun 24 10:15:06 2008
@@ -1,18 +1,19 @@
import itertools
class Accelerator:
- def __init__(self, app, policy):
+ def __init__(self, app, policy, logger):
self.app = app
self.policy = policy
+ self.logger = logger
def __call__(self, environ, start_response):
- def _loggit(msg):
- print >> environ['wsgi.errors'], msg
+ logger = self.logger
result = self.policy.fetch(environ)
if result is not None:
- _loggit('repoze.accelerator: HIT %s' % environ['PATH_INFO'])
+ logger and logger.info(
+ 'repoze.accelerator: HIT %s' % environ['PATH_INFO'])
status, headers, content = result
headers = list(headers) + [('X-Cached-By', 'repoze.accelerator')]
start_response(status, headers)
@@ -20,7 +21,8 @@
yield chunk
raise StopIteration
- _loggit('repoze.accelerator: MISS %s' % environ['PATH_INFO'])
+ logger and logger.info(
+ 'repoze.accelerator: MISS %s' % environ['PATH_INFO'])
catch_response = []
written = []
@@ -57,16 +59,22 @@
def main(app, global_conf, **local_conf):
from repoze.accelerator.storage import make_memory_storage
from repoze.accelerator.policy import make_accelerator_policy
+ from repoze.accelerator.logger import make_logger
+
+ logger_factory = local_conf.get('logger', make_logger)
+ if isinstance(logger_factory, basestring):
+ logger_factory = _resolveEntryPoint(logger_factory)
+ logger = logger_factory(local_conf)
storage_factory = local_conf.get('storage', make_memory_storage)
if isinstance(storage_factory, basestring):
storage_factory = _resolveEntryPoint(storage_factory)
- storage = storage_factory(config=local_conf)
+ storage = storage_factory(logger, local_conf)
policy_factory = local_conf.get('policy', make_accelerator_policy)
if isinstance(policy_factory, basestring):
policy_factory = _resolveEntryPoint(policy_factory)
- policy = policy_factory(storage, config=local_conf)
+ policy = policy_factory(logger, storage, local_conf)
- return Accelerator(app, policy)
+ return Accelerator(app, policy, logger)
Modified: repoze.accelerator/trunk/repoze/accelerator/policy.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/policy.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/policy.py Tue Jun 24 10:15:06 2008
@@ -17,7 +17,7 @@
"""
implements(IPolicy)
- def __init__(self, storage):
+ def __init__(self):
pass
def fetch(self, environ):
@@ -26,8 +26,8 @@
def store(self, status, headers, environ):
pass
-def make_null_policy(storage, config=None):
- return NullPolicy(storage)
+def make_null_policy(logger, storage, config):
+ return NullPolicy()
directlyProvides(make_null_policy, IPolicyFactory)
class AcceleratorPolicy:
@@ -109,6 +109,7 @@
implements(IPolicy)
def __init__(self,
+ logger,
storage,
allowed_methods=('GET',),
always_vary_on_headers=(),
@@ -116,6 +117,7 @@
honor_shift_reload=True,
store_https_responses=False,
):
+ self.logger = logger
self.storage = storage
self.allowed_methods = allowed_methods
self.always_vary_on_headers = always_vary_on_headers
@@ -292,9 +294,7 @@
return False
-def make_accelerator_policy(storage, config=None):
- if config is None:
- config = {}
+def make_accelerator_policy(logger, storage, config):
allowed_methods = config.get('policy.allowed_methods', 'GET')
allowed_methods = [x.upper() for x in
filter(None, allowed_methods.split()) ]
@@ -308,6 +308,7 @@
'REQUEST_METHOD')
always_vary_on_environ = filter(None, always_vary_on_environ.split())
return AcceleratorPolicy(
+ logger,
storage,
allowed_methods,
always_vary_on_headers,
Modified: repoze.accelerator/trunk/repoze/accelerator/storage.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/storage.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/storage.py Tue Jun 24 10:15:06 2008
@@ -10,7 +10,8 @@
class MemoryStorage:
implements(IStorage)
- def __init__(self, lock=threading.Lock()):
+ def __init__(self, logger, lock=threading.Lock()):
+ self.logger = logger
self.data = {}
self.lock = lock
@@ -44,7 +45,7 @@
L.append((status, headers, body, req_d, env_d))
return L
-def make_memory_storage(config=None):
- return MemoryStorage()
+def make_memory_storage(logger, config):
+ return MemoryStorage(logger)
directlyProvides(make_memory_storage, IStorageFactory)
Added: repoze.accelerator/trunk/repoze/accelerator/tests/test_logger.py
==============================================================================
--- (empty file)
+++ repoze.accelerator/trunk/repoze/accelerator/tests/test_logger.py Tue Jun 24 10:15:06 2008
@@ -0,0 +1,81 @@
+import unittest
+
+class TestLoggerFactory(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.accelerator.logger import make_logger
+ return make_logger
+
+ def test_factory_provides_ILoggerFactory(self):
+ from zope.interface.verify import verifyObject
+ from repoze.accelerator.interfaces import ILoggerFactory
+ f = self._getFUT()
+ verifyObject(ILoggerFactory, f)
+
+ def test_default_config(self):
+ f = self._getFUT()
+ result = f({})
+ self.assertEqual(result, None)
+
+ def test_with_envvar(self):
+ import os
+ import logging
+ import sys
+ envvar = 'ACCELERATOR_LOG'
+ try:
+ os.environ[envvar] = '1'
+ f = self._getFUT()
+ logger = f({})
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.assertEqual(logger.handlers[0].stream, sys.stdout)
+ finally:
+ del os.environ[envvar]
+
+ def test_with_stdout_filename(self):
+ import logging
+ import sys
+ f = self._getFUT()
+ config = {'logger.filename':'stdout'}
+ logger = f(config)
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.assertEqual(logger.handlers[0].stream, sys.stdout)
+
+ def test_with_stderr_filename(self):
+ import logging
+ import sys
+ f = self._getFUT()
+ config = {'logger.filename':'stderr'}
+ logger = f(config)
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.assertEqual(logger.handlers[0].stream, sys.stderr)
+
+ def test_with_stderr_filename(self):
+ import logging
+ import sys
+ f = self._getFUT()
+ config = {'logger.filename':'stderr'}
+ logger = f(config)
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.assertEqual(logger.handlers[0].stream, sys.stderr)
+
+ def test_with_real_filename(self):
+ import os
+ import tempfile
+ tfn = tempfile.mktemp()
+ try:
+ import logging
+ f = self._getFUT()
+ config = {'logger.filename':tfn}
+ logger = f(config)
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.failUnless(isinstance(logger.handlers[0].stream, file))
+ finally:
+ os.remove(tfn)
+
+ def test_override_level(self):
+ import logging
+ f = self._getFUT()
+ config = {'logger.filename':'stderr',
+ 'logger.log_level':'DEBUG'}
+ logger = f(config)
+ self.failUnless(isinstance(logger, logging.Logger))
+ self.assertEqual(logger.level, logging.DEBUG)
Modified: repoze.accelerator/trunk/repoze/accelerator/tests/test_middleware.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/tests/test_middleware.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/tests/test_middleware.py Tue Jun 24 10:15:06 2008
@@ -8,7 +8,7 @@
def _makeOne(self, app, policy):
klass = self._getTargetClass()
- return klass(app, policy)
+ return klass(app, policy, None)
def _makeEnviron(self):
@@ -91,6 +91,7 @@
self.failUnless(accel.app is app)
self.failUnless(isinstance(accel.policy, AcceleratorPolicy))
self.failUnless(isinstance(accel.policy.storage, MemoryStorage))
+ self.assertEqual(accel.logger, None)
def test_main_factories(self):
@@ -98,6 +99,7 @@
accel = self._callFUT(app,
{},
+ logger=_makeLogger,
storage=_makeStorage,
policy=_makePolicy,
)
@@ -106,6 +108,7 @@
self.failUnless(isinstance(accel.policy, _Policy))
self.failUnless(isinstance(accel.policy.config, dict))
self.failUnless(isinstance(accel.policy.storage.config, dict))
+ self.failUnless(isinstance(accel.logger, DummyLogger))
def test_main_entry_points(self):
@@ -114,6 +117,7 @@
accel = self._callFUT(
app,
{},
+ logger='repoze.accelerator.tests.test_middleware:_makeLogger',
storage='repoze.accelerator.tests.test_middleware:_makeStorage',
policy='repoze.accelerator.tests.test_middleware:_makePolicy',
)
@@ -122,14 +126,14 @@
self.failUnless(isinstance(accel.policy, _Policy))
self.failUnless(isinstance(accel.policy.config, dict))
self.failUnless(isinstance(accel.policy.storage.config, dict))
+ self.failUnless(isinstance(accel.logger, DummyLogger))
class _Storage:
config = None
-def _makeStorage(config=None):
+def _makeStorage(logger, config):
storage = _Storage()
- if config is not None:
- storage.config = config
+ storage.config = config
return storage
class _Policy:
@@ -138,12 +142,19 @@
def __init__(self, storage):
self.storage = storage
-def _makePolicy(storage, config=None):
+def _makePolicy(logger, storage, config):
policy = _Policy(storage)
- if config is not None:
- policy.config = config
+ policy.config = config
return policy
+class DummyLogger:
+ pass
+
+def _makeLogger(config):
+ logger = DummyLogger()
+ logger.config = config
+ return logger
+
class DummyHandler:
def __init__(self):
self.chunks = []
Modified: repoze.accelerator/trunk/repoze/accelerator/tests/test_policy.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/tests/test_policy.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/tests/test_policy.py Tue Jun 24 10:15:06 2008
@@ -7,7 +7,8 @@
def _makeOne(self, storage):
klass = self._getTargetClass()
- return klass(storage)
+ logger = None
+ return klass(logger, storage)
def _makeEnviron(self):
return {
@@ -423,6 +424,31 @@
result = policy.fetch(environ)
self.assertEqual(result, None)
+ def test_make_accelerator_policy_factory_defaults(self):
+ from repoze.accelerator.policy import make_accelerator_policy
+ policy = make_accelerator_policy(None, DummyStorage(), {})
+ self.assertEqual(policy.allowed_methods, ['GET'])
+ self.assertEqual(policy.honor_shift_reload, False)
+ self.assertEqual(policy.store_https_responses, False)
+ self.assertEqual(policy.always_vary_on_headers, [])
+ self.assertEqual(policy.always_vary_on_environ, ['REQUEST_METHOD'])
+ self.assertEqual(policy.logger, None)
+
+ def test_make_accelerator_policy_factory_overrides(self):
+ from repoze.accelerator.policy import make_accelerator_policy
+ config = {'policy.allowed_methods':'POST GET',
+ 'policy.honor_shift_reload':'true',
+ 'policy.store_https_responses':'true',
+ 'policy.always_vary_on_headers':'Cookie X-Foo',
+ 'policy.always_vary_on_environ':'REMOTE_USER'}
+ policy = make_accelerator_policy(None, DummyStorage(), config)
+ self.assertEqual(policy.allowed_methods, ['POST', 'GET'])
+ self.assertEqual(policy.honor_shift_reload, True)
+ self.assertEqual(policy.store_https_responses, True)
+ self.assertEqual(policy.always_vary_on_headers, ['Cookie', 'X-Foo'])
+ self.assertEqual(policy.always_vary_on_environ, ['REMOTE_USER'])
+ self.assertEqual(policy.logger, None)
+
class DummyStorage:
def __init__(self, fetch_result=None, store_result=None):
self.fetch_result = fetch_result
Modified: repoze.accelerator/trunk/repoze/accelerator/tests/test_storage.py
==============================================================================
--- repoze.accelerator/trunk/repoze/accelerator/tests/test_storage.py (original)
+++ repoze.accelerator/trunk/repoze/accelerator/tests/test_storage.py Tue Jun 24 10:15:06 2008
@@ -9,7 +9,8 @@
def _makeOne(self, lock):
klass = self._getTargetClass()
- return klass(lock)
+ logger = None
+ return klass(logger, lock)
def test_class_conforms_to_IStorage(self):
from zope.interface.verify import verifyClass
@@ -77,6 +78,11 @@
self.assertEqual(result[0], (200, [], [], 1, 2))
self.assertEqual(result[1], (203, [], [], 3, 4))
+ def test_storage_factory_defaults(self):
+ from repoze.accelerator.storage import make_memory_storage
+ storage = make_memory_storage(None, {})
+ self.assertEqual(storage.logger, None)
+
class DummyLock:
def __init__(self):
self.acquired = 0
More information about the Repoze-checkins
mailing list