[CalendarServer-changes] [11380] CalendarServer/trunk/twext/python

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 19 12:18:47 PDT 2013


Revision: 11380
          http://trac.calendarserver.org//changeset/11380
Author:   wsanchez at apple.com
Date:     2013-06-19 12:18:47 -0700 (Wed, 19 Jun 2013)
Log Message:
-----------
LegacyLogger no longer inherrits from Logger.
LegacyLogger passes attribute access up to twisted.python.log.
Add replaceTwistedLoggers.

Modified Paths:
--------------
    CalendarServer/trunk/twext/python/log.py
    CalendarServer/trunk/twext/python/test/test_log.py

Modified: CalendarServer/trunk/twext/python/log.py
===================================================================
--- CalendarServer/trunk/twext/python/log.py	2013-06-18 00:44:18 UTC (rev 11379)
+++ CalendarServer/trunk/twext/python/log.py	2013-06-19 19:18:47 UTC (rev 11380)
@@ -67,9 +67,11 @@
     "FilteringLogObserver",
     "LogLevelFilterPredicate",
     "LegacyLogObserver",
+    "replaceTwistedLoggers",
     #"StandardIOObserver",
 ]
 
+import sys
 from sys import stdout, stderr
 from string import Formatter
 import inspect
@@ -80,6 +82,7 @@
 from twisted.python.constants import NamedConstant, Names
 from twisted.python.failure import Failure
 from twisted.python.reflect import safe_str
+import twisted.python.log
 from twisted.python.log import msg as twistedLogMessage
 from twisted.python.log import addObserver, removeObserver
 from twisted.python.log import ILogObserver as ILegacyLogObserver
@@ -237,6 +240,16 @@
     publisher = lambda e: None
 
 
+    @staticmethod
+    def _namespaceFromCallingContext():
+        """
+        Derive a namespace from the module containing the caller's caller.
+
+        @return: a namespace
+        """
+        return inspect.currentframe().f_back.f_back.f_globals["__name__"]
+
+
     def __init__(self, namespace=None, source=None):
         """
         @param namespace: The namespace for this logger.  Uses a dotted
@@ -248,12 +261,8 @@
             if this L{Logger} is an attribute of that class.
         """
         if namespace is None:
-            currentFrame = inspect.currentframe()
-            callerFrame  = currentFrame.f_back
-            callerModule = callerFrame.f_globals["__name__"]
+            namespace = self._namespaceFromCallingContext()
 
-            namespace = callerModule
-
         self.namespace = namespace
         self.source = source
 
@@ -265,11 +274,17 @@
             # athing.py
             class Something(object):
                 log = Logger()
-                def something(self):
+                def hello(self):
                     self.log.info("Hello")
 
         a L{Logger}'s namespace will be set to the name of the class it is
-        declared on, in this case, C{athing.Something}.
+        declared on.  In the above example, the namespace would be
+        C{athing.Something}.
+
+        Additionally, it's source will be set to the actual object referring to
+        the L{Logger}.  In the above example, C{Something.log.source} would be
+        C{Something}, and C{Something().log.source} would be an instance of
+        C{Something}.
         """
         if oself is None:
             source = type
@@ -358,12 +373,26 @@
 
 
 
-class LegacyLogger(Logger):
+class LegacyLogger(object):
     """
-    A L{Logger} that provides some compatibility with the L{twisted.python.log}
-    module.
+    A logging object that provides some compatibility with the
+    L{twisted.python.log} module.
     """
 
+    def __init__(self, logger=None):
+        if logger is not None:
+            self.newStyleLogger = logger
+        else:
+            self.newStyleLogger = Logger(Logger._namespaceFromCallingContext())
+
+
+    def __getattribute__(self, name):
+        try:
+            return super(LegacyLogger, self).__getattribute__(name)
+        except AttributeError:
+            return getattr(twisted.python.log, name)
+
+
     def msg(self, *message, **kwargs):
         """
         This method is API-compatible with L{twisted.python.log.msg} and exists
@@ -373,7 +402,7 @@
             message = " ".join(map(safe_str, message))
         else:
             message = None
-        return self.emit(LogLevel.info, message, **kwargs)
+        return self.newStyleLogger.emit(LogLevel.info, message, **kwargs)
 
 
     def err(self, _stuff=None, _why=None, **kwargs):
@@ -387,10 +416,10 @@
             _stuff = Failure(_stuff)
 
         if isinstance(_stuff, Failure):
-            self.emit(LogLevel.error, failure=_stuff, why=_why, isError=1, **kwargs)
+            self.newStyleLogger.emit(LogLevel.error, failure=_stuff, why=_why, isError=1, **kwargs)
         else:
             # We got called with an invalid _stuff.
-            self.emit(LogLevel.error, repr(_stuff), why=_why, isError=1, **kwargs)
+            self.newStyleLogger.emit(LogLevel.error, repr(_stuff), why=_why, isError=1, **kwargs)
 
 
 
@@ -811,7 +840,46 @@
 theFormatter = Formatter()
 
 
+def replaceTwistedLoggers():
+    """
+    Visit all Python modules that have been loaded and:
 
+     - replace L{twisted.python.log} with a L{LegacyLogger}
+
+     - replace L{twisted.python.log.msg} with a L{LegacyLogger}'s C{msg}
+
+     - replace L{twisted.python.log.err} with a L{LegacyLogger}'s C{err}
+    """
+    log = Logger()
+
+    for moduleName, module in sys.modules.iteritems():
+        # Oddly, this happens
+        if module is None:
+            continue
+
+        # Don't patch Twisted's logging module
+        if module in (twisted.python, twisted.python.log):
+            continue
+
+        # Don't patch this module
+        if moduleName is __name__:
+            continue
+
+        for name, obj in module.__dict__.iteritems():
+            legacyLogger = LegacyLogger(logger=Logger(namespace=module.__name__))
+
+            if obj is twisted.python.log:
+                log.info("Replacing Twisted log module object {0} in {1}".format(name, module.__name__))
+                setattr(module, name, legacyLogger)
+            elif obj is twisted.python.log.msg:
+                log.info("Replacing Twisted log.msg object {0} in {1}".format(name, module.__name__))
+                setattr(module, name, legacyLogger.msg)
+            elif obj is twisted.python.log.err:
+                log.info("Replacing Twisted log.err object {0} in {1}".format(name, module.__name__))
+                setattr(module, name, legacyLogger.err)
+
+
+
 ######################################################################
 # FIXME: This may not be needed; look into removing it.
 

Modified: CalendarServer/trunk/twext/python/test/test_log.py
===================================================================
--- CalendarServer/trunk/twext/python/test/test_log.py	2013-06-18 00:44:18 UTC (rev 11379)
+++ CalendarServer/trunk/twext/python/test/test_log.py	2013-06-19 19:18:47 UTC (rev 11380)
@@ -39,7 +39,7 @@
 
 
 
-class TestLoggerMixIn(object):
+class TestLogger(Logger):
     def emit(self, level, format=None, **kwargs):
         if False:
             print "*"*60
@@ -66,16 +66,12 @@
 
 
 
-class TestLogger(TestLoggerMixIn, Logger):
-    pass
+class TestLegacyLogger(LegacyLogger):
+    def __init__(self):
+        LegacyLogger.__init__(self, logger=TestLogger())
 
 
 
-class TestLegacyLogger(TestLoggerMixIn, LegacyLogger):
-    pass
-
-
-
 class LogComposedObject(object):
     """
     Just a regular object.
@@ -601,6 +597,21 @@
     Tests for L{LegacyLogger}.
     """
 
+    def test_passThroughAttributes(self):
+        """
+        C{__getattribute__} on L{LegacyLogger} is passing through to Twisted's
+        logging module.
+        """
+        log = TestLegacyLogger()
+
+        # Not passed through
+        self.assertIn("API-compatible", log.msg.__doc__)
+        self.assertIn("API-compatible", log.err.__doc__)
+
+        # Passed through
+        self.assertIdentical(log.addObserver, twistedLogging.addObserver)
+
+
     def test_legacy_msg(self):
         """
         Test LegacyLogger's log.msg()
@@ -612,16 +623,16 @@
 
         log.msg(message, **kwargs)
 
-        self.assertIdentical(log.emitted["level"], LogLevel.info)
-        self.assertEquals(log.emitted["format"], message)
+        self.assertIdentical(log.newStyleLogger.emitted["level"], LogLevel.info)
+        self.assertEquals(log.newStyleLogger.emitted["format"], message)
 
         for key, value in kwargs.items():
-            self.assertIdentical(log.emitted["kwargs"][key], value)
+            self.assertIdentical(log.newStyleLogger.emitted["kwargs"][key], value)
 
         log.msg(foo="")
 
-        self.assertIdentical(log.emitted["level"], LogLevel.info)
-        self.assertIdentical(log.emitted["format"], None)
+        self.assertIdentical(log.newStyleLogger.emitted["level"], LogLevel.info)
+        self.assertIdentical(log.newStyleLogger.emitted["format"], None)
 
 
     def test_legacy_err_implicit(self):
@@ -696,12 +707,12 @@
         errors = self.flushLoggedErrors(exception.__class__)
         self.assertEquals(len(errors), 0)
 
-        self.assertIdentical(log.emitted["level"], LogLevel.error)
-        self.assertEquals(log.emitted["format"], repr(bogus))
-        self.assertIdentical(log.emitted["kwargs"]["why"], why)
+        self.assertIdentical(log.newStyleLogger.emitted["level"], LogLevel.error)
+        self.assertEquals(log.newStyleLogger.emitted["format"], repr(bogus))
+        self.assertIdentical(log.newStyleLogger.emitted["kwargs"]["why"], why)
 
         for key, value in kwargs.items():
-            self.assertIdentical(log.emitted["kwargs"][key], value)
+            self.assertIdentical(log.newStyleLogger.emitted["kwargs"][key], value)
 
 
     def legacy_err(self, log, kwargs, why, exception):
@@ -713,11 +724,11 @@
         errors = self.flushLoggedErrors(exception.__class__)
         self.assertEquals(len(errors), 1)
 
-        self.assertIdentical(log.emitted["level"], LogLevel.error)
-        self.assertEquals(log.emitted["format"], None)
-        self.assertIdentical(log.emitted["kwargs"]["failure"].__class__, Failure)
-        self.assertIdentical(log.emitted["kwargs"]["failure"].value, exception)
-        self.assertIdentical(log.emitted["kwargs"]["why"], why)
+        self.assertIdentical(log.newStyleLogger.emitted["level"], LogLevel.error)
+        self.assertEquals(log.newStyleLogger.emitted["format"], None)
+        self.assertIdentical(log.newStyleLogger.emitted["kwargs"]["failure"].__class__, Failure)
+        self.assertIdentical(log.newStyleLogger.emitted["kwargs"]["failure"].value, exception)
+        self.assertIdentical(log.newStyleLogger.emitted["kwargs"]["why"], why)
 
         for key, value in kwargs.items():
-            self.assertIdentical(log.emitted["kwargs"][key], value)
+            self.assertIdentical(log.newStyleLogger.emitted["kwargs"][key], value)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130619/0e93d358/attachment-0001.html>


More information about the calendarserver-changes mailing list