To use, simply 'import logging' and log away!
"""
-import sys, os, time, io, traceback, warnings
+import sys, os, time, io, traceback, warnings, weakref
__all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO',
__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
__status__ = "production"
-__version__ = "0.5.0.9"
-__date__ = "09 October 2009"
+__version__ = "0.5.1.1"
+__date__ = "25 November 2009"
#---------------------------------------------------------------------------
# Miscellaneous module data
#
#_lock is used to serialize access to shared data structures in this module.
-#This needs to be an RLock because fileConfig() creates Handlers and so
-#might arbitrary user threads. Since Handler.__init__() updates the shared
-#dictionary _handlers, it needs to acquire the lock. But if configuring,
+#This needs to be an RLock because fileConfig() creates and configures
+#Handlers, and so might arbitrary user threads. Since Handler code updates the
+#shared dictionary _handlers, it needs to acquire the lock. But if configuring,
#the lock would already have been acquired - so we need an RLock.
#The same argument applies to Loggers and Manager.loggerDict.
#
# The logging record
#---------------------------------------------------------------------------
-class LogRecord:
+class LogRecord(object):
"""
A LogRecord instance represents an event being logged.
# Formatter classes and functions
#---------------------------------------------------------------------------
-class Formatter:
+class Formatter(object):
"""
Formatter instances are used to convert a LogRecord to text.
#
_defaultFormatter = Formatter()
-class BufferingFormatter:
+class BufferingFormatter(object):
"""
A formatter suitable for formatting a number of records.
"""
# Filter classes and functions
#---------------------------------------------------------------------------
-class Filter:
+class Filter(object):
"""
Filter instances are used to perform arbitrary filtering of LogRecords.
return 0
return (record.name[self.nlen] == ".")
-class Filterer:
+class Filterer(object):
"""
A base class for loggers and handlers which allows them to share
common code.
# Handler classes and functions
#---------------------------------------------------------------------------
-_handlers = {} #repository of handlers (for flushing when shutdown called)
+_handlers = weakref.WeakValueDictionary() #map of handler names to handlers
_handlerList = [] # added to allow handlers to be removed in reverse of order initialized
+def _removeHandlerRef(wr):
+ """
+ Remove a handler reference from the internal cleanup list.
+ """
+ _acquireLock()
+ try:
+ if wr in _handlerList:
+ _handlerList.remove(wr)
+ finally:
+ _releaseLock()
+
+def _addHandlerRef(handler):
+ """
+ Add a handler to the internal cleanup list using a weak reference.
+ """
+ _acquireLock()
+ try:
+ _handlerList.append(weakref.ref(handler, _removeHandlerRef))
+ finally:
+ _releaseLock()
+
class Handler(Filterer):
"""
Handler instances dispatch logging events to specific destinations.
and the filter list to empty.
"""
Filterer.__init__(self)
+ self._name = None
self.level = _checkLevel(level)
self.formatter = None
- #get the module data lock, as we're updating a shared structure.
+ # Add the handler to the global _handlerList (for cleanup on shutdown)
+ _addHandlerRef(self)
+ self.createLock()
+
+ def get_name(self):
+ return self._name
+
+ def set_name(self, name):
_acquireLock()
- try: #unlikely to raise an exception, but you never know...
- _handlers[self] = 1
- _handlerList.insert(0, self)
+ try:
+ if self._name in _handlers:
+ del _handlers[self._name]
+ self._name = name
+ if name:
+ _handlers[name] = self
finally:
_releaseLock()
- self.createLock()
+
+ name = property(get_name, set_name)
def createLock(self):
"""
"""
Tidy up any resources used by the handler.
- This version does removes the handler from an internal list
- of handlers which is closed when shutdown() is called. Subclasses
+ This version removes the handler from an internal map of handlers,
+ _handlers, which is used for handler lookup by name. Subclasses
should ensure that this gets called from overridden close()
methods.
"""
#get the module data lock, as we're updating a shared structure.
_acquireLock()
try: #unlikely to raise an exception, but you never know...
- del _handlers[self]
- _handlerList.remove(self)
+ if self._name and self._name in _handlers:
+ del _handlers[self._name]
finally:
_releaseLock()
# Manager classes and functions
#---------------------------------------------------------------------------
-class PlaceHolder:
+class PlaceHolder(object):
"""
PlaceHolder instances are used in the Manager logger hierarchy to take
the place of nodes for which no loggers have been defined. This class is
return _loggerClass
-class Manager:
+class Manager(object):
"""
There is [under normal circumstances] just one Manager instance, which
holds the hierarchy of loggers.
_loggerClass = Logger
-class LoggerAdapter:
+class LoggerAdapter(object):
"""
An adapter for loggers which makes it easier to specify contextual
information in logging output.
Should be called at application exit.
"""
- for h in handlerList[:]:
+ for wr in reversed(handlerList[:]):
#errors might occur, for example, if files are locked
#we just ignore them if raiseExceptions is not set
try:
+ h = wr()
h.flush()
h.close()
except: