]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/logging/__init__.py
/sys/lib/dist/ndb/common: correct authdom=inri
[plan9front.git] / sys / lib / python / logging / __init__.py
1 # Copyright 2001-2007 by Vinay Sajip. All Rights Reserved.
2 #
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose and without fee is hereby granted,
5 # provided that the above copyright notice appear in all copies and that
6 # both that copyright notice and this permission notice appear in
7 # supporting documentation, and that the name of Vinay Sajip
8 # not be used in advertising or publicity pertaining to distribution
9 # of the software without specific, written prior permission.
10 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
11 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
13 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17 """
18 Logging package for Python. Based on PEP 282 and comments thereto in
19 comp.lang.python, and influenced by Apache's log4j system.
20
21 Should work under Python versions >= 1.5.2, except that source line
22 information is not available unless 'sys._getframe()' is.
23
24 Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved.
25
26 To use, simply 'import logging' and log away!
27 """
28
29 import sys, os, types, time, string, cStringIO, traceback
30
31 try:
32     import codecs
33 except ImportError:
34     codecs = None
35
36 try:
37     import thread
38     import threading
39 except ImportError:
40     thread = None
41
42 __author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"
43 __status__  = "production"
44 __version__ = "0.5.0.2"
45 __date__    = "16 February 2007"
46
47 #---------------------------------------------------------------------------
48 #   Miscellaneous module data
49 #---------------------------------------------------------------------------
50
51 #
52 # _srcfile is used when walking the stack to check when we've got the first
53 # caller stack frame.
54 #
55 if hasattr(sys, 'frozen'): #support for py2exe
56     _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])
57 elif string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
58     _srcfile = __file__[:-4] + '.py'
59 else:
60     _srcfile = __file__
61 _srcfile = os.path.normcase(_srcfile)
62
63 # next bit filched from 1.5.2's inspect.py
64 def currentframe():
65     """Return the frame object for the caller's stack frame."""
66     try:
67         raise Exception
68     except:
69         return sys.exc_traceback.tb_frame.f_back
70
71 if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
72 # done filching
73
74 # _srcfile is only used in conjunction with sys._getframe().
75 # To provide compatibility with older versions of Python, set _srcfile
76 # to None if _getframe() is not available; this value will prevent
77 # findCaller() from being called.
78 #if not hasattr(sys, "_getframe"):
79 #    _srcfile = None
80
81 #
82 #_startTime is used as the base when calculating the relative time of events
83 #
84 _startTime = time.time()
85
86 #
87 #raiseExceptions is used to see if exceptions during handling should be
88 #propagated
89 #
90 raiseExceptions = 1
91
92 #
93 # If you don't want threading information in the log, set this to zero
94 #
95 logThreads = 1
96
97 #
98 # If you don't want process information in the log, set this to zero
99 #
100 logProcesses = 1
101
102 #---------------------------------------------------------------------------
103 #   Level related stuff
104 #---------------------------------------------------------------------------
105 #
106 # Default levels and level names, these can be replaced with any positive set
107 # of values having corresponding names. There is a pseudo-level, NOTSET, which
108 # is only really there as a lower limit for user-defined levels. Handlers and
109 # loggers are initialized with NOTSET so that they will log all messages, even
110 # at user-defined levels.
111 #
112
113 CRITICAL = 50
114 FATAL = CRITICAL
115 ERROR = 40
116 WARNING = 30
117 WARN = WARNING
118 INFO = 20
119 DEBUG = 10
120 NOTSET = 0
121
122 _levelNames = {
123     CRITICAL : 'CRITICAL',
124     ERROR : 'ERROR',
125     WARNING : 'WARNING',
126     INFO : 'INFO',
127     DEBUG : 'DEBUG',
128     NOTSET : 'NOTSET',
129     'CRITICAL' : CRITICAL,
130     'ERROR' : ERROR,
131     'WARN' : WARNING,
132     'WARNING' : WARNING,
133     'INFO' : INFO,
134     'DEBUG' : DEBUG,
135     'NOTSET' : NOTSET,
136 }
137
138 def getLevelName(level):
139     """
140     Return the textual representation of logging level 'level'.
141
142     If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,
143     INFO, DEBUG) then you get the corresponding string. If you have
144     associated levels with names using addLevelName then the name you have
145     associated with 'level' is returned.
146
147     If a numeric value corresponding to one of the defined levels is passed
148     in, the corresponding string representation is returned.
149
150     Otherwise, the string "Level %s" % level is returned.
151     """
152     return _levelNames.get(level, ("Level %s" % level))
153
154 def addLevelName(level, levelName):
155     """
156     Associate 'levelName' with 'level'.
157
158     This is used when converting levels to text during message formatting.
159     """
160     _acquireLock()
161     try:    #unlikely to cause an exception, but you never know...
162         _levelNames[level] = levelName
163         _levelNames[levelName] = level
164     finally:
165         _releaseLock()
166
167 #---------------------------------------------------------------------------
168 #   Thread-related stuff
169 #---------------------------------------------------------------------------
170
171 #
172 #_lock is used to serialize access to shared data structures in this module.
173 #This needs to be an RLock because fileConfig() creates Handlers and so
174 #might arbitrary user threads. Since Handler.__init__() updates the shared
175 #dictionary _handlers, it needs to acquire the lock. But if configuring,
176 #the lock would already have been acquired - so we need an RLock.
177 #The same argument applies to Loggers and Manager.loggerDict.
178 #
179 _lock = None
180
181 def _acquireLock():
182     """
183     Acquire the module-level lock for serializing access to shared data.
184
185     This should be released with _releaseLock().
186     """
187     global _lock
188     if (not _lock) and thread:
189         _lock = threading.RLock()
190     if _lock:
191         _lock.acquire()
192
193 def _releaseLock():
194     """
195     Release the module-level lock acquired by calling _acquireLock().
196     """
197     if _lock:
198         _lock.release()
199
200 #---------------------------------------------------------------------------
201 #   The logging record
202 #---------------------------------------------------------------------------
203
204 class LogRecord:
205     """
206     A LogRecord instance represents an event being logged.
207
208     LogRecord instances are created every time something is logged. They
209     contain all the information pertinent to the event being logged. The
210     main information passed in is in msg and args, which are combined
211     using str(msg) % args to create the message field of the record. The
212     record also includes information such as when the record was created,
213     the source line where the logging call was made, and any exception
214     information to be logged.
215     """
216     def __init__(self, name, level, pathname, lineno,
217                  msg, args, exc_info, func=None):
218         """
219         Initialize a logging record with interesting information.
220         """
221         ct = time.time()
222         self.name = name
223         self.msg = msg
224         #
225         # The following statement allows passing of a dictionary as a sole
226         # argument, so that you can do something like
227         #  logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2})
228         # Suggested by Stefan Behnel.
229         # Note that without the test for args[0], we get a problem because
230         # during formatting, we test to see if the arg is present using
231         # 'if self.args:'. If the event being logged is e.g. 'Value is %d'
232         # and if the passed arg fails 'if self.args:' then no formatting
233         # is done. For example, logger.warn('Value is %d', 0) would log
234         # 'Value is %d' instead of 'Value is 0'.
235         # For the use case of passing a dictionary, this should not be a
236         # problem.
237         if args and (len(args) == 1) and args[0] and (type(args[0]) == types.DictType):
238             args = args[0]
239         self.args = args
240         self.levelname = getLevelName(level)
241         self.levelno = level
242         self.pathname = pathname
243         try:
244             self.filename = os.path.basename(pathname)
245             self.module = os.path.splitext(self.filename)[0]
246         except:
247             self.filename = pathname
248             self.module = "Unknown module"
249         self.exc_info = exc_info
250         self.exc_text = None      # used to cache the traceback text
251         self.lineno = lineno
252         self.funcName = func
253         self.created = ct
254         self.msecs = (ct - long(ct)) * 1000
255         self.relativeCreated = (self.created - _startTime) * 1000
256         if logThreads and thread:
257             self.thread = thread.get_ident()
258             self.threadName = threading.currentThread().getName()
259         else:
260             self.thread = None
261             self.threadName = None
262         if logProcesses and hasattr(os, 'getpid'):
263             self.process = os.getpid()
264         else:
265             self.process = None
266
267     def __str__(self):
268         return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
269             self.pathname, self.lineno, self.msg)
270
271     def getMessage(self):
272         """
273         Return the message for this LogRecord.
274
275         Return the message for this LogRecord after merging any user-supplied
276         arguments with the message.
277         """
278         if not hasattr(types, "UnicodeType"): #if no unicode support...
279             msg = str(self.msg)
280         else:
281             msg = self.msg
282             if type(msg) not in (types.UnicodeType, types.StringType):
283                 try:
284                     msg = str(self.msg)
285                 except UnicodeError:
286                     msg = self.msg      #Defer encoding till later
287         if self.args:
288             msg = msg % self.args
289         return msg
290
291 def makeLogRecord(dict):
292     """
293     Make a LogRecord whose attributes are defined by the specified dictionary,
294     This function is useful for converting a logging event received over
295     a socket connection (which is sent as a dictionary) into a LogRecord
296     instance.
297     """
298     rv = LogRecord(None, None, "", 0, "", (), None, None)
299     rv.__dict__.update(dict)
300     return rv
301
302 #---------------------------------------------------------------------------
303 #   Formatter classes and functions
304 #---------------------------------------------------------------------------
305
306 class Formatter:
307     """
308     Formatter instances are used to convert a LogRecord to text.
309
310     Formatters need to know how a LogRecord is constructed. They are
311     responsible for converting a LogRecord to (usually) a string which can
312     be interpreted by either a human or an external system. The base Formatter
313     allows a formatting string to be specified. If none is supplied, the
314     default value of "%s(message)\\n" is used.
315
316     The Formatter can be initialized with a format string which makes use of
317     knowledge of the LogRecord attributes - e.g. the default value mentioned
318     above makes use of the fact that the user's message and arguments are pre-
319     formatted into a LogRecord's message attribute. Currently, the useful
320     attributes in a LogRecord are described by:
321
322     %(name)s            Name of the logger (logging channel)
323     %(levelno)s         Numeric logging level for the message (DEBUG, INFO,
324                         WARNING, ERROR, CRITICAL)
325     %(levelname)s       Text logging level for the message ("DEBUG", "INFO",
326                         "WARNING", "ERROR", "CRITICAL")
327     %(pathname)s        Full pathname of the source file where the logging
328                         call was issued (if available)
329     %(filename)s        Filename portion of pathname
330     %(module)s          Module (name portion of filename)
331     %(lineno)d          Source line number where the logging call was issued
332                         (if available)
333     %(funcName)s        Function name
334     %(created)f         Time when the LogRecord was created (time.time()
335                         return value)
336     %(asctime)s         Textual time when the LogRecord was created
337     %(msecs)d           Millisecond portion of the creation time
338     %(relativeCreated)d Time in milliseconds when the LogRecord was created,
339                         relative to the time the logging module was loaded
340                         (typically at application startup time)
341     %(thread)d          Thread ID (if available)
342     %(threadName)s      Thread name (if available)
343     %(process)d         Process ID (if available)
344     %(message)s         The result of record.getMessage(), computed just as
345                         the record is emitted
346     """
347
348     converter = time.localtime
349
350     def __init__(self, fmt=None, datefmt=None):
351         """
352         Initialize the formatter with specified format strings.
353
354         Initialize the formatter either with the specified format string, or a
355         default as described above. Allow for specialized date formatting with
356         the optional datefmt argument (if omitted, you get the ISO8601 format).
357         """
358         if fmt:
359             self._fmt = fmt
360         else:
361             self._fmt = "%(message)s"
362         self.datefmt = datefmt
363
364     def formatTime(self, record, datefmt=None):
365         """
366         Return the creation time of the specified LogRecord as formatted text.
367
368         This method should be called from format() by a formatter which
369         wants to make use of a formatted time. This method can be overridden
370         in formatters to provide for any specific requirement, but the
371         basic behaviour is as follows: if datefmt (a string) is specified,
372         it is used with time.strftime() to format the creation time of the
373         record. Otherwise, the ISO8601 format is used. The resulting
374         string is returned. This function uses a user-configurable function
375         to convert the creation time to a tuple. By default, time.localtime()
376         is used; to change this for a particular formatter instance, set the
377         'converter' attribute to a function with the same signature as
378         time.localtime() or time.gmtime(). To change it for all formatters,
379         for example if you want all logging times to be shown in GMT,
380         set the 'converter' attribute in the Formatter class.
381         """
382         ct = self.converter(record.created)
383         if datefmt:
384             s = time.strftime(datefmt, ct)
385         else:
386             t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
387             s = "%s,%03d" % (t, record.msecs)
388         return s
389
390     def formatException(self, ei):
391         """
392         Format and return the specified exception information as a string.
393
394         This default implementation just uses
395         traceback.print_exception()
396         """
397         sio = cStringIO.StringIO()
398         traceback.print_exception(ei[0], ei[1], ei[2], None, sio)
399         s = sio.getvalue()
400         sio.close()
401         if s[-1] == "\n":
402             s = s[:-1]
403         return s
404
405     def format(self, record):
406         """
407         Format the specified record as text.
408
409         The record's attribute dictionary is used as the operand to a
410         string formatting operation which yields the returned string.
411         Before formatting the dictionary, a couple of preparatory steps
412         are carried out. The message attribute of the record is computed
413         using LogRecord.getMessage(). If the formatting string contains
414         "%(asctime)", formatTime() is called to format the event time.
415         If there is exception information, it is formatted using
416         formatException() and appended to the message.
417         """
418         record.message = record.getMessage()
419         if string.find(self._fmt,"%(asctime)") >= 0:
420             record.asctime = self.formatTime(record, self.datefmt)
421         s = self._fmt % record.__dict__
422         if record.exc_info:
423             # Cache the traceback text to avoid converting it multiple times
424             # (it's constant anyway)
425             if not record.exc_text:
426                 record.exc_text = self.formatException(record.exc_info)
427         if record.exc_text:
428             if s[-1] != "\n":
429                 s = s + "\n"
430             s = s + record.exc_text
431         return s
432
433 #
434 #   The default formatter to use when no other is specified
435 #
436 _defaultFormatter = Formatter()
437
438 class BufferingFormatter:
439     """
440     A formatter suitable for formatting a number of records.
441     """
442     def __init__(self, linefmt=None):
443         """
444         Optionally specify a formatter which will be used to format each
445         individual record.
446         """
447         if linefmt:
448             self.linefmt = linefmt
449         else:
450             self.linefmt = _defaultFormatter
451
452     def formatHeader(self, records):
453         """
454         Return the header string for the specified records.
455         """
456         return ""
457
458     def formatFooter(self, records):
459         """
460         Return the footer string for the specified records.
461         """
462         return ""
463
464     def format(self, records):
465         """
466         Format the specified records and return the result as a string.
467         """
468         rv = ""
469         if len(records) > 0:
470             rv = rv + self.formatHeader(records)
471             for record in records:
472                 rv = rv + self.linefmt.format(record)
473             rv = rv + self.formatFooter(records)
474         return rv
475
476 #---------------------------------------------------------------------------
477 #   Filter classes and functions
478 #---------------------------------------------------------------------------
479
480 class Filter:
481     """
482     Filter instances are used to perform arbitrary filtering of LogRecords.
483
484     Loggers and Handlers can optionally use Filter instances to filter
485     records as desired. The base filter class only allows events which are
486     below a certain point in the logger hierarchy. For example, a filter
487     initialized with "A.B" will allow events logged by loggers "A.B",
488     "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If
489     initialized with the empty string, all events are passed.
490     """
491     def __init__(self, name=''):
492         """
493         Initialize a filter.
494
495         Initialize with the name of the logger which, together with its
496         children, will have its events allowed through the filter. If no
497         name is specified, allow every event.
498         """
499         self.name = name
500         self.nlen = len(name)
501
502     def filter(self, record):
503         """
504         Determine if the specified record is to be logged.
505
506         Is the specified record to be logged? Returns 0 for no, nonzero for
507         yes. If deemed appropriate, the record may be modified in-place.
508         """
509         if self.nlen == 0:
510             return 1
511         elif self.name == record.name:
512             return 1
513         elif string.find(record.name, self.name, 0, self.nlen) != 0:
514             return 0
515         return (record.name[self.nlen] == ".")
516
517 class Filterer:
518     """
519     A base class for loggers and handlers which allows them to share
520     common code.
521     """
522     def __init__(self):
523         """
524         Initialize the list of filters to be an empty list.
525         """
526         self.filters = []
527
528     def addFilter(self, filter):
529         """
530         Add the specified filter to this handler.
531         """
532         if not (filter in self.filters):
533             self.filters.append(filter)
534
535     def removeFilter(self, filter):
536         """
537         Remove the specified filter from this handler.
538         """
539         if filter in self.filters:
540             self.filters.remove(filter)
541
542     def filter(self, record):
543         """
544         Determine if a record is loggable by consulting all the filters.
545
546         The default is to allow the record to be logged; any filter can veto
547         this and the record is then dropped. Returns a zero value if a record
548         is to be dropped, else non-zero.
549         """
550         rv = 1
551         for f in self.filters:
552             if not f.filter(record):
553                 rv = 0
554                 break
555         return rv
556
557 #---------------------------------------------------------------------------
558 #   Handler classes and functions
559 #---------------------------------------------------------------------------
560
561 _handlers = {}  #repository of handlers (for flushing when shutdown called)
562 _handlerList = [] # added to allow handlers to be removed in reverse of order initialized
563
564 class Handler(Filterer):
565     """
566     Handler instances dispatch logging events to specific destinations.
567
568     The base handler class. Acts as a placeholder which defines the Handler
569     interface. Handlers can optionally use Formatter instances to format
570     records as desired. By default, no formatter is specified; in this case,
571     the 'raw' message as determined by record.message is logged.
572     """
573     def __init__(self, level=NOTSET):
574         """
575         Initializes the instance - basically setting the formatter to None
576         and the filter list to empty.
577         """
578         Filterer.__init__(self)
579         self.level = level
580         self.formatter = None
581         #get the module data lock, as we're updating a shared structure.
582         _acquireLock()
583         try:    #unlikely to raise an exception, but you never know...
584             _handlers[self] = 1
585             _handlerList.insert(0, self)
586         finally:
587             _releaseLock()
588         self.createLock()
589
590     def createLock(self):
591         """
592         Acquire a thread lock for serializing access to the underlying I/O.
593         """
594         if thread:
595             self.lock = threading.RLock()
596         else:
597             self.lock = None
598
599     def acquire(self):
600         """
601         Acquire the I/O thread lock.
602         """
603         if self.lock:
604             self.lock.acquire()
605
606     def release(self):
607         """
608         Release the I/O thread lock.
609         """
610         if self.lock:
611             self.lock.release()
612
613     def setLevel(self, level):
614         """
615         Set the logging level of this handler.
616         """
617         self.level = level
618
619     def format(self, record):
620         """
621         Format the specified record.
622
623         If a formatter is set, use it. Otherwise, use the default formatter
624         for the module.
625         """
626         if self.formatter:
627             fmt = self.formatter
628         else:
629             fmt = _defaultFormatter
630         return fmt.format(record)
631
632     def emit(self, record):
633         """
634         Do whatever it takes to actually log the specified logging record.
635
636         This version is intended to be implemented by subclasses and so
637         raises a NotImplementedError.
638         """
639         raise NotImplementedError, 'emit must be implemented '\
640                                     'by Handler subclasses'
641
642     def handle(self, record):
643         """
644         Conditionally emit the specified logging record.
645
646         Emission depends on filters which may have been added to the handler.
647         Wrap the actual emission of the record with acquisition/release of
648         the I/O thread lock. Returns whether the filter passed the record for
649         emission.
650         """
651         rv = self.filter(record)
652         if rv:
653             self.acquire()
654             try:
655                 self.emit(record)
656             finally:
657                 self.release()
658         return rv
659
660     def setFormatter(self, fmt):
661         """
662         Set the formatter for this handler.
663         """
664         self.formatter = fmt
665
666     def flush(self):
667         """
668         Ensure all logging output has been flushed.
669
670         This version does nothing and is intended to be implemented by
671         subclasses.
672         """
673         pass
674
675     def close(self):
676         """
677         Tidy up any resources used by the handler.
678
679         This version does removes the handler from an internal list
680         of handlers which is closed when shutdown() is called. Subclasses
681         should ensure that this gets called from overridden close()
682         methods.
683         """
684         #get the module data lock, as we're updating a shared structure.
685         _acquireLock()
686         try:    #unlikely to raise an exception, but you never know...
687             del _handlers[self]
688             _handlerList.remove(self)
689         finally:
690             _releaseLock()
691
692     def handleError(self, record):
693         """
694         Handle errors which occur during an emit() call.
695
696         This method should be called from handlers when an exception is
697         encountered during an emit() call. If raiseExceptions is false,
698         exceptions get silently ignored. This is what is mostly wanted
699         for a logging system - most users will not care about errors in
700         the logging system, they are more interested in application errors.
701         You could, however, replace this with a custom handler if you wish.
702         The record which was being processed is passed in to this method.
703         """
704         if raiseExceptions:
705             ei = sys.exc_info()
706             traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr)
707             del ei
708
709 class StreamHandler(Handler):
710     """
711     A handler class which writes logging records, appropriately formatted,
712     to a stream. Note that this class does not close the stream, as
713     sys.stdout or sys.stderr may be used.
714     """
715     def __init__(self, strm=None):
716         """
717         Initialize the handler.
718
719         If strm is not specified, sys.stderr is used.
720         """
721         Handler.__init__(self)
722         if strm is None:
723             strm = sys.stderr
724         self.stream = strm
725         self.formatter = None
726
727     def flush(self):
728         """
729         Flushes the stream.
730         """
731         self.stream.flush()
732
733     def emit(self, record):
734         """
735         Emit a record.
736
737         If a formatter is specified, it is used to format the record.
738         The record is then written to the stream with a trailing newline
739         [N.B. this may be removed depending on feedback]. If exception
740         information is present, it is formatted using
741         traceback.print_exception and appended to the stream.
742         """
743         try:
744             msg = self.format(record)
745             fs = "%s\n"
746             if not hasattr(types, "UnicodeType"): #if no unicode support...
747                 self.stream.write(fs % msg)
748             else:
749                 try:
750                     self.stream.write(fs % msg)
751                 except UnicodeError:
752                     self.stream.write(fs % msg.encode("UTF-8"))
753             self.flush()
754         except (KeyboardInterrupt, SystemExit):
755             raise
756         except:
757             self.handleError(record)
758
759 class FileHandler(StreamHandler):
760     """
761     A handler class which writes formatted logging records to disk files.
762     """
763     def __init__(self, filename, mode='a', encoding=None):
764         """
765         Open the specified file and use it as the stream for logging.
766         """
767         if codecs is None:
768             encoding = None
769         if encoding is None:
770             stream = open(filename, mode)
771         else:
772             stream = codecs.open(filename, mode, encoding)
773         StreamHandler.__init__(self, stream)
774         #keep the absolute path, otherwise derived classes which use this
775         #may come a cropper when the current directory changes
776         self.baseFilename = os.path.abspath(filename)
777         self.mode = mode
778
779     def close(self):
780         """
781         Closes the stream.
782         """
783         self.flush()
784         self.stream.close()
785         StreamHandler.close(self)
786
787 #---------------------------------------------------------------------------
788 #   Manager classes and functions
789 #---------------------------------------------------------------------------
790
791 class PlaceHolder:
792     """
793     PlaceHolder instances are used in the Manager logger hierarchy to take
794     the place of nodes for which no loggers have been defined. This class is
795     intended for internal use only and not as part of the public API.
796     """
797     def __init__(self, alogger):
798         """
799         Initialize with the specified logger being a child of this placeholder.
800         """
801         #self.loggers = [alogger]
802         self.loggerMap = { alogger : None }
803
804     def append(self, alogger):
805         """
806         Add the specified logger as a child of this placeholder.
807         """
808         #if alogger not in self.loggers:
809         if not self.loggerMap.has_key(alogger):
810             #self.loggers.append(alogger)
811             self.loggerMap[alogger] = None
812
813 #
814 #   Determine which class to use when instantiating loggers.
815 #
816 _loggerClass = None
817
818 def setLoggerClass(klass):
819     """
820     Set the class to be used when instantiating a logger. The class should
821     define __init__() such that only a name argument is required, and the
822     __init__() should call Logger.__init__()
823     """
824     if klass != Logger:
825         if not issubclass(klass, Logger):
826             raise TypeError, "logger not derived from logging.Logger: " + \
827                             klass.__name__
828     global _loggerClass
829     _loggerClass = klass
830
831 def getLoggerClass():
832     """
833     Return the class to be used when instantiating a logger.
834     """
835
836     return _loggerClass
837
838 class Manager:
839     """
840     There is [under normal circumstances] just one Manager instance, which
841     holds the hierarchy of loggers.
842     """
843     def __init__(self, rootnode):
844         """
845         Initialize the manager with the root node of the logger hierarchy.
846         """
847         self.root = rootnode
848         self.disable = 0
849         self.emittedNoHandlerWarning = 0
850         self.loggerDict = {}
851
852     def getLogger(self, name):
853         """
854         Get a logger with the specified name (channel name), creating it
855         if it doesn't yet exist. This name is a dot-separated hierarchical
856         name, such as "a", "a.b", "a.b.c" or similar.
857
858         If a PlaceHolder existed for the specified name [i.e. the logger
859         didn't exist but a child of it did], replace it with the created
860         logger and fix up the parent/child references which pointed to the
861         placeholder to now point to the logger.
862         """
863         rv = None
864         _acquireLock()
865         try:
866             if self.loggerDict.has_key(name):
867                 rv = self.loggerDict[name]
868                 if isinstance(rv, PlaceHolder):
869                     ph = rv
870                     rv = _loggerClass(name)
871                     rv.manager = self
872                     self.loggerDict[name] = rv
873                     self._fixupChildren(ph, rv)
874                     self._fixupParents(rv)
875             else:
876                 rv = _loggerClass(name)
877                 rv.manager = self
878                 self.loggerDict[name] = rv
879                 self._fixupParents(rv)
880         finally:
881             _releaseLock()
882         return rv
883
884     def _fixupParents(self, alogger):
885         """
886         Ensure that there are either loggers or placeholders all the way
887         from the specified logger to the root of the logger hierarchy.
888         """
889         name = alogger.name
890         i = string.rfind(name, ".")
891         rv = None
892         while (i > 0) and not rv:
893             substr = name[:i]
894             if not self.loggerDict.has_key(substr):
895                 self.loggerDict[substr] = PlaceHolder(alogger)
896             else:
897                 obj = self.loggerDict[substr]
898                 if isinstance(obj, Logger):
899                     rv = obj
900                 else:
901                     assert isinstance(obj, PlaceHolder)
902                     obj.append(alogger)
903             i = string.rfind(name, ".", 0, i - 1)
904         if not rv:
905             rv = self.root
906         alogger.parent = rv
907
908     def _fixupChildren(self, ph, alogger):
909         """
910         Ensure that children of the placeholder ph are connected to the
911         specified logger.
912         """
913         name = alogger.name
914         namelen = len(name)
915         for c in ph.loggerMap.keys():
916             #The if means ... if not c.parent.name.startswith(nm)
917             #if string.find(c.parent.name, nm) <> 0:
918             if c.parent.name[:namelen] != name:
919                 alogger.parent = c.parent
920                 c.parent = alogger
921
922 #---------------------------------------------------------------------------
923 #   Logger classes and functions
924 #---------------------------------------------------------------------------
925
926 class Logger(Filterer):
927     """
928     Instances of the Logger class represent a single logging channel. A
929     "logging channel" indicates an area of an application. Exactly how an
930     "area" is defined is up to the application developer. Since an
931     application can have any number of areas, logging channels are identified
932     by a unique string. Application areas can be nested (e.g. an area
933     of "input processing" might include sub-areas "read CSV files", "read
934     XLS files" and "read Gnumeric files"). To cater for this natural nesting,
935     channel names are organized into a namespace hierarchy where levels are
936     separated by periods, much like the Java or Python package namespace. So
937     in the instance given above, channel names might be "input" for the upper
938     level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
939     There is no arbitrary limit to the depth of nesting.
940     """
941     def __init__(self, name, level=NOTSET):
942         """
943         Initialize the logger with a name and an optional level.
944         """
945         Filterer.__init__(self)
946         self.name = name
947         self.level = level
948         self.parent = None
949         self.propagate = 1
950         self.handlers = []
951         self.disabled = 0
952
953     def setLevel(self, level):
954         """
955         Set the logging level of this logger.
956         """
957         self.level = level
958
959     def debug(self, msg, *args, **kwargs):
960         """
961         Log 'msg % args' with severity 'DEBUG'.
962
963         To pass exception information, use the keyword argument exc_info with
964         a true value, e.g.
965
966         logger.debug("Houston, we have a %s", "thorny problem", exc_info=1)
967         """
968         if self.manager.disable >= DEBUG:
969             return
970         if DEBUG >= self.getEffectiveLevel():
971             apply(self._log, (DEBUG, msg, args), kwargs)
972
973     def info(self, msg, *args, **kwargs):
974         """
975         Log 'msg % args' with severity 'INFO'.
976
977         To pass exception information, use the keyword argument exc_info with
978         a true value, e.g.
979
980         logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
981         """
982         if self.manager.disable >= INFO:
983             return
984         if INFO >= self.getEffectiveLevel():
985             apply(self._log, (INFO, msg, args), kwargs)
986
987     def warning(self, msg, *args, **kwargs):
988         """
989         Log 'msg % args' with severity 'WARNING'.
990
991         To pass exception information, use the keyword argument exc_info with
992         a true value, e.g.
993
994         logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1)
995         """
996         if self.manager.disable >= WARNING:
997             return
998         if self.isEnabledFor(WARNING):
999             apply(self._log, (WARNING, msg, args), kwargs)
1000
1001     warn = warning
1002
1003     def error(self, msg, *args, **kwargs):
1004         """
1005         Log 'msg % args' with severity 'ERROR'.
1006
1007         To pass exception information, use the keyword argument exc_info with
1008         a true value, e.g.
1009
1010         logger.error("Houston, we have a %s", "major problem", exc_info=1)
1011         """
1012         if self.manager.disable >= ERROR:
1013             return
1014         if self.isEnabledFor(ERROR):
1015             apply(self._log, (ERROR, msg, args), kwargs)
1016
1017     def exception(self, msg, *args):
1018         """
1019         Convenience method for logging an ERROR with exception information.
1020         """
1021         apply(self.error, (msg,) + args, {'exc_info': 1})
1022
1023     def critical(self, msg, *args, **kwargs):
1024         """
1025         Log 'msg % args' with severity 'CRITICAL'.
1026
1027         To pass exception information, use the keyword argument exc_info with
1028         a true value, e.g.
1029
1030         logger.critical("Houston, we have a %s", "major disaster", exc_info=1)
1031         """
1032         if self.manager.disable >= CRITICAL:
1033             return
1034         if CRITICAL >= self.getEffectiveLevel():
1035             apply(self._log, (CRITICAL, msg, args), kwargs)
1036
1037     fatal = critical
1038
1039     def log(self, level, msg, *args, **kwargs):
1040         """
1041         Log 'msg % args' with the integer severity 'level'.
1042
1043         To pass exception information, use the keyword argument exc_info with
1044         a true value, e.g.
1045
1046         logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
1047         """
1048         if type(level) != types.IntType:
1049             if raiseExceptions:
1050                 raise TypeError, "level must be an integer"
1051             else:
1052                 return
1053         if self.manager.disable >= level:
1054             return
1055         if self.isEnabledFor(level):
1056             apply(self._log, (level, msg, args), kwargs)
1057
1058     def findCaller(self):
1059         """
1060         Find the stack frame of the caller so that we can note the source
1061         file name, line number and function name.
1062         """
1063         f = currentframe().f_back
1064         rv = "(unknown file)", 0, "(unknown function)"
1065         while hasattr(f, "f_code"):
1066             co = f.f_code
1067             filename = os.path.normcase(co.co_filename)
1068             if filename == _srcfile:
1069                 f = f.f_back
1070                 continue
1071             rv = (filename, f.f_lineno, co.co_name)
1072             break
1073         return rv
1074
1075     def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
1076         """
1077         A factory method which can be overridden in subclasses to create
1078         specialized LogRecords.
1079         """
1080         rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
1081         if extra:
1082             for key in extra:
1083                 if (key in ["message", "asctime"]) or (key in rv.__dict__):
1084                     raise KeyError("Attempt to overwrite %r in LogRecord" % key)
1085                 rv.__dict__[key] = extra[key]
1086         return rv
1087
1088     def _log(self, level, msg, args, exc_info=None, extra=None):
1089         """
1090         Low-level logging routine which creates a LogRecord and then calls
1091         all the handlers of this logger to handle the record.
1092         """
1093         if _srcfile:
1094             fn, lno, func = self.findCaller()
1095         else:
1096             fn, lno, func = "(unknown file)", 0, "(unknown function)"
1097         if exc_info:
1098             if type(exc_info) != types.TupleType:
1099                 exc_info = sys.exc_info()
1100         record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
1101         self.handle(record)
1102
1103     def handle(self, record):
1104         """
1105         Call the handlers for the specified record.
1106
1107         This method is used for unpickled records received from a socket, as
1108         well as those created locally. Logger-level filtering is applied.
1109         """
1110         if (not self.disabled) and self.filter(record):
1111             self.callHandlers(record)
1112
1113     def addHandler(self, hdlr):
1114         """
1115         Add the specified handler to this logger.
1116         """
1117         if not (hdlr in self.handlers):
1118             self.handlers.append(hdlr)
1119
1120     def removeHandler(self, hdlr):
1121         """
1122         Remove the specified handler from this logger.
1123         """
1124         if hdlr in self.handlers:
1125             #hdlr.close()
1126             hdlr.acquire()
1127             try:
1128                 self.handlers.remove(hdlr)
1129             finally:
1130                 hdlr.release()
1131
1132     def callHandlers(self, record):
1133         """
1134         Pass a record to all relevant handlers.
1135
1136         Loop through all handlers for this logger and its parents in the
1137         logger hierarchy. If no handler was found, output a one-off error
1138         message to sys.stderr. Stop searching up the hierarchy whenever a
1139         logger with the "propagate" attribute set to zero is found - that
1140         will be the last logger whose handlers are called.
1141         """
1142         c = self
1143         found = 0
1144         while c:
1145             for hdlr in c.handlers:
1146                 found = found + 1
1147                 if record.levelno >= hdlr.level:
1148                     hdlr.handle(record)
1149             if not c.propagate:
1150                 c = None    #break out
1151             else:
1152                 c = c.parent
1153         if (found == 0) and raiseExceptions and not self.manager.emittedNoHandlerWarning:
1154             sys.stderr.write("No handlers could be found for logger"
1155                              " \"%s\"\n" % self.name)
1156             self.manager.emittedNoHandlerWarning = 1
1157
1158     def getEffectiveLevel(self):
1159         """
1160         Get the effective level for this logger.
1161
1162         Loop through this logger and its parents in the logger hierarchy,
1163         looking for a non-zero logging level. Return the first one found.
1164         """
1165         logger = self
1166         while logger:
1167             if logger.level:
1168                 return logger.level
1169             logger = logger.parent
1170         return NOTSET
1171
1172     def isEnabledFor(self, level):
1173         """
1174         Is this logger enabled for level 'level'?
1175         """
1176         if self.manager.disable >= level:
1177             return 0
1178         return level >= self.getEffectiveLevel()
1179
1180 class RootLogger(Logger):
1181     """
1182     A root logger is not that different to any other logger, except that
1183     it must have a logging level and there is only one instance of it in
1184     the hierarchy.
1185     """
1186     def __init__(self, level):
1187         """
1188         Initialize the logger with the name "root".
1189         """
1190         Logger.__init__(self, "root", level)
1191
1192 _loggerClass = Logger
1193
1194 root = RootLogger(WARNING)
1195 Logger.root = root
1196 Logger.manager = Manager(Logger.root)
1197
1198 #---------------------------------------------------------------------------
1199 # Configuration classes and functions
1200 #---------------------------------------------------------------------------
1201
1202 BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s"
1203
1204 def basicConfig(**kwargs):
1205     """
1206     Do basic configuration for the logging system.
1207
1208     This function does nothing if the root logger already has handlers
1209     configured. It is a convenience method intended for use by simple scripts
1210     to do one-shot configuration of the logging package.
1211
1212     The default behaviour is to create a StreamHandler which writes to
1213     sys.stderr, set a formatter using the BASIC_FORMAT format string, and
1214     add the handler to the root logger.
1215
1216     A number of optional keyword arguments may be specified, which can alter
1217     the default behaviour.
1218
1219     filename  Specifies that a FileHandler be created, using the specified
1220               filename, rather than a StreamHandler.
1221     filemode  Specifies the mode to open the file, if filename is specified
1222               (if filemode is unspecified, it defaults to 'a').
1223     format    Use the specified format string for the handler.
1224     datefmt   Use the specified date/time format.
1225     level     Set the root logger level to the specified level.
1226     stream    Use the specified stream to initialize the StreamHandler. Note
1227               that this argument is incompatible with 'filename' - if both
1228               are present, 'stream' is ignored.
1229
1230     Note that you could specify a stream created using open(filename, mode)
1231     rather than passing the filename and mode in. However, it should be
1232     remembered that StreamHandler does not close its stream (since it may be
1233     using sys.stdout or sys.stderr), whereas FileHandler closes its stream
1234     when the handler is closed.
1235     """
1236     if len(root.handlers) == 0:
1237         filename = kwargs.get("filename")
1238         if filename:
1239             mode = kwargs.get("filemode", 'a')
1240             hdlr = FileHandler(filename, mode)
1241         else:
1242             stream = kwargs.get("stream")
1243             hdlr = StreamHandler(stream)
1244         fs = kwargs.get("format", BASIC_FORMAT)
1245         dfs = kwargs.get("datefmt", None)
1246         fmt = Formatter(fs, dfs)
1247         hdlr.setFormatter(fmt)
1248         root.addHandler(hdlr)
1249         level = kwargs.get("level")
1250         if level:
1251             root.setLevel(level)
1252
1253 #---------------------------------------------------------------------------
1254 # Utility functions at module level.
1255 # Basically delegate everything to the root logger.
1256 #---------------------------------------------------------------------------
1257
1258 def getLogger(name=None):
1259     """
1260     Return a logger with the specified name, creating it if necessary.
1261
1262     If no name is specified, return the root logger.
1263     """
1264     if name:
1265         return Logger.manager.getLogger(name)
1266     else:
1267         return root
1268
1269 #def getRootLogger():
1270 #    """
1271 #    Return the root logger.
1272 #
1273 #    Note that getLogger('') now does the same thing, so this function is
1274 #    deprecated and may disappear in the future.
1275 #    """
1276 #    return root
1277
1278 def critical(msg, *args, **kwargs):
1279     """
1280     Log a message with severity 'CRITICAL' on the root logger.
1281     """
1282     if len(root.handlers) == 0:
1283         basicConfig()
1284     apply(root.critical, (msg,)+args, kwargs)
1285
1286 fatal = critical
1287
1288 def error(msg, *args, **kwargs):
1289     """
1290     Log a message with severity 'ERROR' on the root logger.
1291     """
1292     if len(root.handlers) == 0:
1293         basicConfig()
1294     apply(root.error, (msg,)+args, kwargs)
1295
1296 def exception(msg, *args):
1297     """
1298     Log a message with severity 'ERROR' on the root logger,
1299     with exception information.
1300     """
1301     apply(error, (msg,)+args, {'exc_info': 1})
1302
1303 def warning(msg, *args, **kwargs):
1304     """
1305     Log a message with severity 'WARNING' on the root logger.
1306     """
1307     if len(root.handlers) == 0:
1308         basicConfig()
1309     apply(root.warning, (msg,)+args, kwargs)
1310
1311 warn = warning
1312
1313 def info(msg, *args, **kwargs):
1314     """
1315     Log a message with severity 'INFO' on the root logger.
1316     """
1317     if len(root.handlers) == 0:
1318         basicConfig()
1319     apply(root.info, (msg,)+args, kwargs)
1320
1321 def debug(msg, *args, **kwargs):
1322     """
1323     Log a message with severity 'DEBUG' on the root logger.
1324     """
1325     if len(root.handlers) == 0:
1326         basicConfig()
1327     apply(root.debug, (msg,)+args, kwargs)
1328
1329 def log(level, msg, *args, **kwargs):
1330     """
1331     Log 'msg % args' with the integer severity 'level' on the root logger.
1332     """
1333     if len(root.handlers) == 0:
1334         basicConfig()
1335     apply(root.log, (level, msg)+args, kwargs)
1336
1337 def disable(level):
1338     """
1339     Disable all logging calls less severe than 'level'.
1340     """
1341     root.manager.disable = level
1342
1343 def shutdown(handlerList=_handlerList):
1344     """
1345     Perform any cleanup actions in the logging system (e.g. flushing
1346     buffers).
1347
1348     Should be called at application exit.
1349     """
1350     for h in handlerList[:]:
1351         #errors might occur, for example, if files are locked
1352         #we just ignore them if raiseExceptions is not set
1353         try:
1354             h.flush()
1355             h.close()
1356         except:
1357             if raiseExceptions:
1358                 raise
1359             #else, swallow
1360
1361 #Let's try and shutdown automatically on application exit...
1362 try:
1363     import atexit
1364     atexit.register(shutdown)
1365 except ImportError: # for Python versions < 2.0
1366     def exithook(status, old_exit=sys.exit):
1367         try:
1368             shutdown()
1369         finally:
1370             old_exit(status)
1371
1372     sys.exit = exithook