2323To use, simply 'import logging' and log away!
2424"""
2525
26- import sys , os , time , io , traceback , warnings
26+ import sys , os , time , io , traceback , warnings , weakref
2727
2828__all__ = ['BASIC_FORMAT' , 'BufferingFormatter' , 'CRITICAL' , 'DEBUG' , 'ERROR' ,
2929 'FATAL' , 'FileHandler' , 'Filter' , 'Formatter' , 'Handler' , 'INFO' ,
4646
4747__author__ = "Vinay Sajip <[email protected] >" 4848__status__ = "production"
49- __version__ = "0.5.0.9 "
50- __date__ = "09 October 2009"
49+ __version__ = "0.5.1.1 "
50+ __date__ = "25 November 2009"
5151
5252#---------------------------------------------------------------------------
5353# Miscellaneous module data
@@ -193,9 +193,9 @@ def _checkLevel(level):
193193
194194#
195195#_lock is used to serialize access to shared data structures in this module.
196- #This needs to be an RLock because fileConfig() creates Handlers and so
197- #might arbitrary user threads. Since Handler.__init__() updates the shared
198- #dictionary _handlers, it needs to acquire the lock. But if configuring,
196+ #This needs to be an RLock because fileConfig() creates and configures
197+ #Handlers, and so might arbitrary user threads. Since Handler code updates the
198+ #shared dictionary _handlers, it needs to acquire the lock. But if configuring,
199199#the lock would already have been acquired - so we need an RLock.
200200#The same argument applies to Loggers and Manager.loggerDict.
201201#
@@ -224,7 +224,7 @@ def _releaseLock():
224224# The logging record
225225#---------------------------------------------------------------------------
226226
227- class LogRecord :
227+ class LogRecord ( object ) :
228228 """
229229 A LogRecord instance represents an event being logged.
230230
@@ -332,7 +332,7 @@ def makeLogRecord(dict):
332332# Formatter classes and functions
333333#---------------------------------------------------------------------------
334334
335- class Formatter :
335+ class Formatter ( object ) :
336336 """
337337 Formatter instances are used to convert a LogRecord to text.
338338
@@ -464,7 +464,7 @@ def format(self, record):
464464#
465465_defaultFormatter = Formatter ()
466466
467- class BufferingFormatter :
467+ class BufferingFormatter ( object ) :
468468 """
469469 A formatter suitable for formatting a number of records.
470470 """
@@ -506,7 +506,7 @@ def format(self, records):
506506# Filter classes and functions
507507#---------------------------------------------------------------------------
508508
509- class Filter :
509+ class Filter ( object ) :
510510 """
511511 Filter instances are used to perform arbitrary filtering of LogRecords.
512512
@@ -543,7 +543,7 @@ def filter(self, record):
543543 return 0
544544 return (record .name [self .nlen ] == "." )
545545
546- class Filterer :
546+ class Filterer ( object ) :
547547 """
548548 A base class for loggers and handlers which allows them to share
549549 common code.
@@ -587,9 +587,30 @@ def filter(self, record):
587587# Handler classes and functions
588588#---------------------------------------------------------------------------
589589
590- _handlers = {} #repository of handlers (for flushing when shutdown called)
590+ _handlers = weakref . WeakValueDictionary () #map of handler names to handlers
591591_handlerList = [] # added to allow handlers to be removed in reverse of order initialized
592592
593+ def _removeHandlerRef (wr ):
594+ """
595+ Remove a handler reference from the internal cleanup list.
596+ """
597+ _acquireLock ()
598+ try :
599+ if wr in _handlerList :
600+ _handlerList .remove (wr )
601+ finally :
602+ _releaseLock ()
603+
604+ def _addHandlerRef (handler ):
605+ """
606+ Add a handler to the internal cleanup list using a weak reference.
607+ """
608+ _acquireLock ()
609+ try :
610+ _handlerList .append (weakref .ref (handler , _removeHandlerRef ))
611+ finally :
612+ _releaseLock ()
613+
593614class Handler (Filterer ):
594615 """
595616 Handler instances dispatch logging events to specific destinations.
@@ -605,16 +626,28 @@ def __init__(self, level=NOTSET):
605626 and the filter list to empty.
606627 """
607628 Filterer .__init__ (self )
629+ self ._name = None
608630 self .level = _checkLevel (level )
609631 self .formatter = None
610- #get the module data lock, as we're updating a shared structure.
632+ # Add the handler to the global _handlerList (for cleanup on shutdown)
633+ _addHandlerRef (self )
634+ self .createLock ()
635+
636+ def get_name (self ):
637+ return self ._name
638+
639+ def set_name (self , name ):
611640 _acquireLock ()
612- try : #unlikely to raise an exception, but you never know...
613- _handlers [self ] = 1
614- _handlerList .insert (0 , self )
641+ try :
642+ if self ._name in _handlers :
643+ del _handlers [self ._name ]
644+ self ._name = name
645+ if name :
646+ _handlers [name ] = self
615647 finally :
616648 _releaseLock ()
617- self .createLock ()
649+
650+ name = property (get_name , set_name )
618651
619652 def createLock (self ):
620653 """
@@ -705,16 +738,16 @@ def close(self):
705738 """
706739 Tidy up any resources used by the handler.
707740
708- This version does removes the handler from an internal list
709- of handlers which is closed when shutdown() is called . Subclasses
741+ This version removes the handler from an internal map of handlers,
742+ _handlers, which is used for handler lookup by name . Subclasses
710743 should ensure that this gets called from overridden close()
711744 methods.
712745 """
713746 #get the module data lock, as we're updating a shared structure.
714747 _acquireLock ()
715748 try : #unlikely to raise an exception, but you never know...
716- del _handlers [ self ]
717- _handlerList . remove ( self )
749+ if self . _name and self . _name in _handlers :
750+ del _handlers [ self . _name ]
718751 finally :
719752 _releaseLock ()
720753
@@ -866,7 +899,7 @@ def emit(self, record):
866899# Manager classes and functions
867900#---------------------------------------------------------------------------
868901
869- class PlaceHolder :
902+ class PlaceHolder ( object ) :
870903 """
871904 PlaceHolder instances are used in the Manager logger hierarchy to take
872905 the place of nodes for which no loggers have been defined. This class is
@@ -913,7 +946,7 @@ def getLoggerClass():
913946
914947 return _loggerClass
915948
916- class Manager :
949+ class Manager ( object ) :
917950 """
918951 There is [under normal circumstances] just one Manager instance, which
919952 holds the hierarchy of loggers.
@@ -1266,7 +1299,7 @@ def __init__(self, level):
12661299
12671300_loggerClass = Logger
12681301
1269- class LoggerAdapter :
1302+ class LoggerAdapter ( object ) :
12701303 """
12711304 An adapter for loggers which makes it easier to specify contextual
12721305 information in logging output.
@@ -1512,10 +1545,11 @@ def shutdown(handlerList=_handlerList):
15121545
15131546 Should be called at application exit.
15141547 """
1515- for h in handlerList [:]:
1548+ for wr in reversed ( handlerList [:]) :
15161549 #errors might occur, for example, if files are locked
15171550 #we just ignore them if raiseExceptions is not set
15181551 try :
1552+ h = wr ()
15191553 h .flush ()
15201554 h .close ()
15211555 except :
0 commit comments