[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