| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | # Copyright 2001-2002 by Vinay Sajip. All Rights Reserved. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Permission to use, copy, modify, and distribute this software and its | 
					
						
							|  |  |  | # documentation for any purpose and without fee is hereby granted, | 
					
						
							|  |  |  | # provided that the above copyright notice appear in all copies and that | 
					
						
							|  |  |  | # both that copyright notice and this permission notice appear in | 
					
						
							|  |  |  | # supporting documentation, and that the name of Vinay Sajip | 
					
						
							|  |  |  | # not be used in advertising or publicity pertaining to distribution | 
					
						
							|  |  |  | # of the software without specific, written prior permission. | 
					
						
							|  |  |  | # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | 
					
						
							|  |  |  | # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | 
					
						
							|  |  |  | # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | 
					
						
							|  |  |  | # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | 
					
						
							|  |  |  | # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | 
					
						
							|  |  |  | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | Logging package for Python. Based on PEP 282 and comments thereto in | 
					
						
							|  |  |  | comp.lang.python, and influenced by Apache's log4j system. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Should work under Python versions >= 1.5.2, except that source line | 
					
						
							| 
									
										
										
										
											2003-01-23 18:29:29 +00:00
										 |  |  | information is not available unless 'sys._getframe()' is. | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Copyright (C) 2001-2002 Vinay Sajip. All Rights Reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To use, simply 'import logging' and log away! | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-15 23:31:28 +00:00
										 |  |  | import sys, os, types, time, string, cStringIO | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     import thread | 
					
						
							|  |  |  |     import threading | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     thread = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __author__  = "Vinay Sajip <vinay_sajip@red-dove.com>" | 
					
						
							|  |  |  | __status__  = "alpha" | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | __version__ = "0.4.8" | 
					
						
							|  |  |  | __date__    = "16 February 2003" | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Miscellaneous module data | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # _verinfo is used for when behaviour needs to be adjusted to the version | 
					
						
							|  |  |  | # of Python | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _verinfo = getattr(sys, "version_info", None) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | # | 
					
						
							|  |  |  | #_srcfile is used when walking the stack to check when we've got the first | 
					
						
							|  |  |  | # caller stack frame. | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2002-11-13 16:18:29 +00:00
										 |  |  | if string.lower(__file__[-4:]) in ['.pyc', '.pyo']: | 
					
						
							|  |  |  |     _srcfile = __file__[:-4] + '.py' | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | else: | 
					
						
							| 
									
										
										
										
											2002-11-13 16:18:29 +00:00
										 |  |  |     _srcfile = __file__ | 
					
						
							|  |  |  | _srcfile = os.path.normcase(_srcfile) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-23 18:29:29 +00:00
										 |  |  | # _srcfile is only used in conjunction with sys._getframe(). | 
					
						
							|  |  |  | # To provide compatibility with older versions of Python, set _srcfile | 
					
						
							|  |  |  | # to None if _getframe() is not available; this value will prevent | 
					
						
							|  |  |  | # findCaller() from being called. | 
					
						
							|  |  |  | if not hasattr(sys, "_getframe"): | 
					
						
							|  |  |  |     _srcfile = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | # | 
					
						
							|  |  |  | #_startTime is used as the base when calculating the relative time of events | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | _startTime = time.time() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #raiseExceptions is used to see if exceptions during handling should be | 
					
						
							|  |  |  | #propagated | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | raiseExceptions = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Level related stuff | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Default levels and level names, these can be replaced with any positive set | 
					
						
							|  |  |  | # of values having corresponding names. There is a pseudo-level, NOTSET, which | 
					
						
							|  |  |  | # is only really there as a lower limit for user-defined levels. Handlers and | 
					
						
							|  |  |  | # loggers are initialized with NOTSET so that they will log all messages, even | 
					
						
							|  |  |  | # at user-defined levels. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | CRITICAL = 50 | 
					
						
							|  |  |  | FATAL = CRITICAL | 
					
						
							|  |  |  | ERROR = 40 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | WARNING = 30 | 
					
						
							|  |  |  | WARN = WARNING | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | INFO = 20 | 
					
						
							|  |  |  | DEBUG = 10 | 
					
						
							|  |  |  | NOTSET = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _levelNames = { | 
					
						
							|  |  |  |     CRITICAL : 'CRITICAL', | 
					
						
							|  |  |  |     ERROR : 'ERROR', | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     WARNING : 'WARNING', | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     INFO : 'INFO', | 
					
						
							|  |  |  |     DEBUG : 'DEBUG', | 
					
						
							|  |  |  |     NOTSET : 'NOTSET', | 
					
						
							|  |  |  |     'CRITICAL' : CRITICAL, | 
					
						
							|  |  |  |     'ERROR' : ERROR, | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     'WARN' : WARNING, | 
					
						
							|  |  |  |     'WARNING' : WARNING, | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     'INFO' : INFO, | 
					
						
							|  |  |  |     'DEBUG' : DEBUG, | 
					
						
							|  |  |  |     'NOTSET' : NOTSET, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def getLevelName(level): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Return the textual representation of logging level 'level'. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     If the level is one of the predefined levels (CRITICAL, ERROR, WARNING, | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     INFO, DEBUG) then you get the corresponding string. If you have | 
					
						
							|  |  |  |     associated levels with names using addLevelName then the name you have | 
					
						
							|  |  |  |     associated with 'level' is returned. Otherwise, the string | 
					
						
							|  |  |  |     "Level %s" % level is returned. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     return _levelNames.get(level, ("Level %s" % level)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def addLevelName(level, levelName): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Associate 'levelName' with 'level'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This is used when converting levels to text during message formatting. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     _acquireLock() | 
					
						
							|  |  |  |     try:    #unlikely to cause an exception, but you never know... | 
					
						
							|  |  |  |         _levelNames[level] = levelName | 
					
						
							|  |  |  |         _levelNames[levelName] = level | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         _releaseLock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Thread-related stuff | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #_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, | 
					
						
							|  |  |  | #the lock would already have been acquired - so we need an RLock. | 
					
						
							|  |  |  | #The same argument applies to Loggers and Manager.loggerDict. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | _lock = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _acquireLock(): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Acquire the module-level lock for serializing access to shared data. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This should be released with _releaseLock(). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     global _lock | 
					
						
							|  |  |  |     if (not _lock) and thread: | 
					
						
							|  |  |  |         _lock = threading.RLock() | 
					
						
							|  |  |  |     if _lock: | 
					
						
							|  |  |  |         _lock.acquire() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _releaseLock(): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Release the module-level lock acquired by calling _acquireLock(). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if _lock: | 
					
						
							|  |  |  |         _lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   The logging record | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LogRecord: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A LogRecord instance represents an event being logged. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LogRecord instances are created every time something is logged. They | 
					
						
							|  |  |  |     contain all the information pertinent to the event being logged. The | 
					
						
							|  |  |  |     main information passed in is in msg and args, which are combined | 
					
						
							|  |  |  |     using str(msg) % args to create the message field of the record. The | 
					
						
							|  |  |  |     record also includes information such as when the record was created, | 
					
						
							|  |  |  |     the source line where the logging call was made, and any exception | 
					
						
							|  |  |  |     information to be logged. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, name, level, pathname, lineno, msg, args, exc_info): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize a logging record with interesting information. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         ct = time.time() | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.msg = msg | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |         self.levelname = getLevelName(level) | 
					
						
							|  |  |  |         self.levelno = level | 
					
						
							|  |  |  |         self.pathname = pathname | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.filename = os.path.basename(pathname) | 
					
						
							|  |  |  |             self.module = os.path.splitext(self.filename)[0] | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             self.filename = pathname | 
					
						
							|  |  |  |             self.module = "Unknown module" | 
					
						
							|  |  |  |         self.exc_info = exc_info | 
					
						
							|  |  |  |         self.lineno = lineno | 
					
						
							|  |  |  |         self.created = ct | 
					
						
							|  |  |  |         self.msecs = (ct - long(ct)) * 1000 | 
					
						
							|  |  |  |         self.relativeCreated = (self.created - _startTime) * 1000 | 
					
						
							|  |  |  |         if thread: | 
					
						
							|  |  |  |             self.thread = thread.get_ident() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.thread = None | 
					
						
							| 
									
										
										
										
											2003-02-21 22:29:45 +00:00
										 |  |  |         if hasattr(os, 'getpid'): | 
					
						
							|  |  |  |             self.process = os.getpid() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.process = None | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno, | 
					
						
							|  |  |  |             self.pathname, self.lineno, self.msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getMessage(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the message for this LogRecord. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Return the message for this LogRecord after merging any user-supplied | 
					
						
							|  |  |  |         arguments with the message. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         if not hasattr(types, "UnicodeType"): #if no unicode support... | 
					
						
							|  |  |  |             msg = str(self.msg) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 msg = str(self.msg) | 
					
						
							|  |  |  |             except UnicodeError: | 
					
						
							|  |  |  |                 msg = self.msg      #Defer encoding till later | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         if self.args: | 
					
						
							|  |  |  |             msg = msg % self.args | 
					
						
							|  |  |  |         return msg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Formatter classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Formatter: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Formatter instances are used to convert a LogRecord to text. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Formatters need to know how a LogRecord is constructed. They are | 
					
						
							|  |  |  |     responsible for converting a LogRecord to (usually) a string which can | 
					
						
							|  |  |  |     be interpreted by either a human or an external system. The base Formatter | 
					
						
							|  |  |  |     allows a formatting string to be specified. If none is supplied, the | 
					
						
							|  |  |  |     default value of "%s(message)\\n" is used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The Formatter can be initialized with a format string which makes use of | 
					
						
							|  |  |  |     knowledge of the LogRecord attributes - e.g. the default value mentioned | 
					
						
							|  |  |  |     above makes use of the fact that the user's message and arguments are pre- | 
					
						
							|  |  |  |     formatted into a LogRecord's message attribute. Currently, the useful | 
					
						
							|  |  |  |     attributes in a LogRecord are described by: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     %(name)s            Name of the logger (logging channel) | 
					
						
							|  |  |  |     %(levelno)s         Numeric logging level for the message (DEBUG, INFO, | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |                         WARNING, ERROR, CRITICAL) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     %(levelname)s       Text logging level for the message ("DEBUG", "INFO", | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |                         "WARNING", "ERROR", "CRITICAL") | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     %(pathname)s        Full pathname of the source file where the logging | 
					
						
							|  |  |  |                         call was issued (if available) | 
					
						
							|  |  |  |     %(filename)s        Filename portion of pathname | 
					
						
							|  |  |  |     %(module)s          Module (name portion of filename) | 
					
						
							|  |  |  |     %(lineno)d          Source line number where the logging call was issued | 
					
						
							|  |  |  |                         (if available) | 
					
						
							|  |  |  |     %(created)f         Time when the LogRecord was created (time.time() | 
					
						
							|  |  |  |                         return value) | 
					
						
							|  |  |  |     %(asctime)s         Textual time when the LogRecord was created | 
					
						
							|  |  |  |     %(msecs)d           Millisecond portion of the creation time | 
					
						
							|  |  |  |     %(relativeCreated)d Time in milliseconds when the LogRecord was created, | 
					
						
							|  |  |  |                         relative to the time the logging module was loaded | 
					
						
							|  |  |  |                         (typically at application startup time) | 
					
						
							|  |  |  |     %(thread)d          Thread ID (if available) | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     %(process)d         Process ID (if available) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     %(message)s         The result of record.getMessage(), computed just as | 
					
						
							|  |  |  |                         the record is emitted | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     converter = time.localtime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, fmt=None, datefmt=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the formatter with specified format strings. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Initialize the formatter either with the specified format string, or a | 
					
						
							|  |  |  |         default as described above. Allow for specialized date formatting with | 
					
						
							|  |  |  |         the optional datefmt argument (if omitted, you get the ISO8601 format). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if fmt: | 
					
						
							|  |  |  |             self._fmt = fmt | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self._fmt = "%(message)s" | 
					
						
							|  |  |  |         self.datefmt = datefmt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def formatTime(self, record, datefmt=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the creation time of the specified LogRecord as formatted text. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This method should be called from format() by a formatter which | 
					
						
							|  |  |  |         wants to make use of a formatted time. This method can be overridden | 
					
						
							|  |  |  |         in formatters to provide for any specific requirement, but the | 
					
						
							|  |  |  |         basic behaviour is as follows: if datefmt (a string) is specified, | 
					
						
							|  |  |  |         it is used with time.strftime() to format the creation time of the | 
					
						
							|  |  |  |         record. Otherwise, the ISO8601 format is used. The resulting | 
					
						
							|  |  |  |         string is returned. This function uses a user-configurable function | 
					
						
							|  |  |  |         to convert the creation time to a tuple. By default, time.localtime() | 
					
						
							|  |  |  |         is used; to change this for a particular formatter instance, set the | 
					
						
							|  |  |  |         'converter' attribute to a function with the same signature as | 
					
						
							|  |  |  |         time.localtime() or time.gmtime(). To change it for all formatters, | 
					
						
							|  |  |  |         for example if you want all logging times to be shown in GMT, | 
					
						
							|  |  |  |         set the 'converter' attribute in the Formatter class. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         ct = self.converter(record.created) | 
					
						
							|  |  |  |         if datefmt: | 
					
						
							|  |  |  |             s = time.strftime(datefmt, ct) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             t = time.strftime("%Y-%m-%d %H:%M:%S", ct) | 
					
						
							|  |  |  |             s = "%s,%03d" % (t, record.msecs) | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def formatException(self, ei): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Format and return the specified exception information as a string. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This default implementation just uses | 
					
						
							|  |  |  |         traceback.print_exception() | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         import traceback | 
					
						
							|  |  |  |         sio = cStringIO.StringIO() | 
					
						
							|  |  |  |         traceback.print_exception(ei[0], ei[1], ei[2], None, sio) | 
					
						
							|  |  |  |         s = sio.getvalue() | 
					
						
							|  |  |  |         sio.close() | 
					
						
							|  |  |  |         if s[-1] == "\n": | 
					
						
							|  |  |  |             s = s[:-1] | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def format(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Format the specified record as text. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The record's attribute dictionary is used as the operand to a | 
					
						
							|  |  |  |         string formatting operation which yields the returned string. | 
					
						
							|  |  |  |         Before formatting the dictionary, a couple of preparatory steps | 
					
						
							|  |  |  |         are carried out. The message attribute of the record is computed | 
					
						
							|  |  |  |         using LogRecord.getMessage(). If the formatting string contains | 
					
						
							|  |  |  |         "%(asctime)", formatTime() is called to format the event time. | 
					
						
							|  |  |  |         If there is exception information, it is formatted using | 
					
						
							|  |  |  |         formatException() and appended to the message. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         record.message = record.getMessage() | 
					
						
							|  |  |  |         if string.find(self._fmt,"%(asctime)") >= 0: | 
					
						
							|  |  |  |             record.asctime = self.formatTime(record, self.datefmt) | 
					
						
							|  |  |  |         s = self._fmt % record.__dict__ | 
					
						
							|  |  |  |         if record.exc_info: | 
					
						
							|  |  |  |             if s[-1] != "\n": | 
					
						
							|  |  |  |                 s = s + "\n" | 
					
						
							|  |  |  |             s = s + self.formatException(record.exc_info) | 
					
						
							|  |  |  |         return s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #   The default formatter to use when no other is specified | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | _defaultFormatter = Formatter() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BufferingFormatter: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A formatter suitable for formatting a number of records. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, linefmt=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Optionally specify a formatter which will be used to format each | 
					
						
							|  |  |  |         individual record. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if linefmt: | 
					
						
							|  |  |  |             self.linefmt = linefmt | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.linefmt = _defaultFormatter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def formatHeader(self, records): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the header string for the specified records. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def formatFooter(self, records): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Return the footer string for the specified records. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def format(self, records): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Format the specified records and return the result as a string. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         rv = "" | 
					
						
							|  |  |  |         if len(records) > 0: | 
					
						
							|  |  |  |             rv = rv + self.formatHeader(records) | 
					
						
							|  |  |  |             for record in records: | 
					
						
							|  |  |  |                 rv = rv + self.linefmt.format(record) | 
					
						
							|  |  |  |             rv = rv + self.formatFooter(records) | 
					
						
							|  |  |  |         return rv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Filter classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Filter: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Filter instances are used to perform arbitrary filtering of LogRecords. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Loggers and Handlers can optionally use Filter instances to filter | 
					
						
							|  |  |  |     records as desired. The base filter class only allows events which are | 
					
						
							|  |  |  |     below a certain point in the logger hierarchy. For example, a filter | 
					
						
							|  |  |  |     initialized with "A.B" will allow events logged by loggers "A.B", | 
					
						
							|  |  |  |     "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If | 
					
						
							|  |  |  |     initialized with the empty string, all events are passed. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, name=''): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize a filter. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Initialize with the name of the logger which, together with its | 
					
						
							|  |  |  |         children, will have its events allowed through the filter. If no | 
					
						
							|  |  |  |         name is specified, allow every event. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.nlen = len(name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def filter(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Determine if the specified record is to be logged. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Is the specified record to be logged? Returns 0 for no, nonzero for | 
					
						
							|  |  |  |         yes. If deemed appropriate, the record may be modified in-place. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.nlen == 0: | 
					
						
							|  |  |  |             return 1 | 
					
						
							|  |  |  |         elif self.name == record.name: | 
					
						
							|  |  |  |             return 1 | 
					
						
							|  |  |  |         elif string.find(record.name, self.name, 0, self.nlen) != 0: | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         return (record.name[self.nlen] == ".") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Filterer: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A base class for loggers and handlers which allows them to share | 
					
						
							|  |  |  |     common code. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the list of filters to be an empty list. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.filters = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def addFilter(self, filter): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Add the specified filter to this handler. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if not (filter in self.filters): | 
					
						
							|  |  |  |             self.filters.append(filter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def removeFilter(self, filter): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Remove the specified filter from this handler. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if filter in self.filters: | 
					
						
							|  |  |  |             self.filters.remove(filter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def filter(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Determine if a record is loggable by consulting all the filters. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         The default is to allow the record to be logged; any filter can veto | 
					
						
							|  |  |  |         this and the record is then dropped. Returns a zero value if a record | 
					
						
							|  |  |  |         is to be dropped, else non-zero. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         rv = 1 | 
					
						
							|  |  |  |         for f in self.filters: | 
					
						
							|  |  |  |             if not f.filter(record): | 
					
						
							|  |  |  |                 rv = 0 | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         return rv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Handler classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _handlers = {}  #repository of handlers (for flushing when shutdown called) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Handler(Filterer): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Handler instances dispatch logging events to specific destinations. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The base handler class. Acts as a placeholder which defines the Handler | 
					
						
							|  |  |  |     interface. Handlers can optionally use Formatter instances to format | 
					
						
							|  |  |  |     records as desired. By default, no formatter is specified; in this case, | 
					
						
							|  |  |  |     the 'raw' message as determined by record.message is logged. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, level=NOTSET): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initializes the instance - basically setting the formatter to None | 
					
						
							|  |  |  |         and the filter list to empty. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Filterer.__init__(self) | 
					
						
							|  |  |  |         self.level = level | 
					
						
							|  |  |  |         self.formatter = None | 
					
						
							|  |  |  |         #get the module data lock, as we're updating a shared structure. | 
					
						
							|  |  |  |         _acquireLock() | 
					
						
							|  |  |  |         try:    #unlikely to raise an exception, but you never know... | 
					
						
							|  |  |  |             _handlers[self] = 1 | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             _releaseLock() | 
					
						
							|  |  |  |         self.createLock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def createLock(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Acquire a thread lock for serializing access to the underlying I/O. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if thread: | 
					
						
							|  |  |  |             self.lock = thread.allocate_lock() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.lock = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def acquire(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Acquire the I/O thread lock. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.lock: | 
					
						
							|  |  |  |             self.lock.acquire() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def release(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Release the I/O thread lock. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.lock: | 
					
						
							|  |  |  |             self.lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setLevel(self, level): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Set the logging level of this handler. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.level = level | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def format(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Format the specified record. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If a formatter is set, use it. Otherwise, use the default formatter | 
					
						
							|  |  |  |         for the module. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.formatter: | 
					
						
							|  |  |  |             fmt = self.formatter | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             fmt = _defaultFormatter | 
					
						
							|  |  |  |         return fmt.format(record) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def emit(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Do whatever it takes to actually log the specified logging record. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This version is intended to be implemented by subclasses and so | 
					
						
							|  |  |  |         raises a NotImplementedError. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         raise NotImplementedError, 'emit must be implemented '\ | 
					
						
							|  |  |  |                                     'by Handler subclasses' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def handle(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Conditionally emit the specified logging record. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Emission depends on filters which may have been added to the handler. | 
					
						
							|  |  |  |         Wrap the actual emission of the record with acquisition/release of | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         the I/O thread lock. Returns whether the filter passed the record for | 
					
						
							|  |  |  |         emission. | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         rv = self.filter(record) | 
					
						
							|  |  |  |         if rv: | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |             self.acquire() | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.emit(record) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 self.release() | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         return rv | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def setFormatter(self, fmt): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Set the formatter for this handler. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.formatter = fmt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def flush(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Ensure all logging output has been flushed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This version does nothing and is intended to be implemented by | 
					
						
							|  |  |  |         subclasses. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Tidy up any resources used by the handler. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This version does nothing and is intended to be implemented by | 
					
						
							|  |  |  |         subclasses. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     def handleError(self, record): | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Handle errors which occur during an emit() call. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This method should be called from handlers when an exception is | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         encountered during an emit() call. If raiseExceptions is false, | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         exceptions get silently ignored. This is what is mostly wanted | 
					
						
							|  |  |  |         for a logging system - most users will not care about errors in | 
					
						
							|  |  |  |         the logging system, they are more interested in application errors. | 
					
						
							|  |  |  |         You could, however, replace this with a custom handler if you wish. | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         The record which was being processed is passed in to this method. | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         if raiseExceptions: | 
					
						
							|  |  |  |             import traceback | 
					
						
							|  |  |  |             ei = sys.exc_info() | 
					
						
							|  |  |  |             traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) | 
					
						
							|  |  |  |             del ei | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StreamHandler(Handler): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A handler class which writes logging records, appropriately formatted, | 
					
						
							|  |  |  |     to a stream. Note that this class does not close the stream, as | 
					
						
							|  |  |  |     sys.stdout or sys.stderr may be used. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, strm=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the handler. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If strm is not specified, sys.stderr is used. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handler.__init__(self) | 
					
						
							|  |  |  |         if not strm: | 
					
						
							|  |  |  |             strm = sys.stderr | 
					
						
							|  |  |  |         self.stream = strm | 
					
						
							|  |  |  |         self.formatter = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def flush(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Flushes the stream. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.stream.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def emit(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Emit a record. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If a formatter is specified, it is used to format the record. | 
					
						
							|  |  |  |         The record is then written to the stream with a trailing newline | 
					
						
							|  |  |  |         [N.B. this may be removed depending on feedback]. If exception | 
					
						
							|  |  |  |         information is present, it is formatted using | 
					
						
							|  |  |  |         traceback.print_exception and appended to the stream. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             msg = self.format(record) | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |             if not hasattr(types, "UnicodeType"): #if no unicode support... | 
					
						
							|  |  |  |                 self.stream.write("%s\n" % msg) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     self.stream.write("%s\n" % msg) | 
					
						
							|  |  |  |                 except UnicodeError: | 
					
						
							|  |  |  |                     self.stream.write("%s\n" % msg.encode("UTF-8")) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |             self.flush() | 
					
						
							|  |  |  |         except: | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |             self.handleError(record) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FileHandler(StreamHandler): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A handler class which writes formatted logging records to disk files. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, filename, mode="a"): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Open the specified file and use it as the stream for logging. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         StreamHandler.__init__(self, open(filename, mode)) | 
					
						
							|  |  |  |         self.baseFilename = filename | 
					
						
							|  |  |  |         self.mode = mode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Closes the stream. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.stream.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Manager classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PlaceHolder: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     PlaceHolder instances are used in the Manager logger hierarchy to take | 
					
						
							|  |  |  |     the place of nodes for which no loggers have been defined [FIXME add | 
					
						
							|  |  |  |     example]. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, alogger): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize with the specified logger being a child of this placeholder. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.loggers = [alogger] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def append(self, alogger): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Add the specified logger as a child of this placeholder. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if alogger not in self.loggers: | 
					
						
							|  |  |  |             self.loggers.append(alogger) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #   Determine which class to use when instantiating loggers. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | _loggerClass = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def setLoggerClass(klass): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Set the class to be used when instantiating a logger. The class should | 
					
						
							|  |  |  |     define __init__() such that only a name argument is required, and the | 
					
						
							|  |  |  |     __init__() should call Logger.__init__() | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if klass != Logger: | 
					
						
							|  |  |  |         if type(klass) != types.ClassType: | 
					
						
							|  |  |  |             raise TypeError, "setLoggerClass is expecting a class" | 
					
						
							|  |  |  |         if not issubclass(klass, Logger): | 
					
						
							|  |  |  |             raise TypeError, "logger not derived from logging.Logger: " + \ | 
					
						
							|  |  |  |                             klass.__name__ | 
					
						
							|  |  |  |     global _loggerClass | 
					
						
							|  |  |  |     _loggerClass = klass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Manager: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     There is [under normal circumstances] just one Manager instance, which | 
					
						
							|  |  |  |     holds the hierarchy of loggers. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2002-11-15 23:31:28 +00:00
										 |  |  |     def __init__(self, rootnode): | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the manager with the root node of the logger hierarchy. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2002-11-15 23:31:28 +00:00
										 |  |  |         self.root = rootnode | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         self.disable = 0 | 
					
						
							|  |  |  |         self.emittedNoHandlerWarning = 0 | 
					
						
							|  |  |  |         self.loggerDict = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getLogger(self, name): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Get a logger with the specified name (channel name), creating it | 
					
						
							|  |  |  |         if it doesn't yet exist. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If a PlaceHolder existed for the specified name [i.e. the logger | 
					
						
							|  |  |  |         didn't exist but a child of it did], replace it with the created | 
					
						
							|  |  |  |         logger and fix up the parent/child references which pointed to the | 
					
						
							|  |  |  |         placeholder to now point to the logger. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         rv = None | 
					
						
							|  |  |  |         _acquireLock() | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             if self.loggerDict.has_key(name): | 
					
						
							|  |  |  |                 rv = self.loggerDict[name] | 
					
						
							|  |  |  |                 if isinstance(rv, PlaceHolder): | 
					
						
							|  |  |  |                     ph = rv | 
					
						
							|  |  |  |                     rv = _loggerClass(name) | 
					
						
							|  |  |  |                     rv.manager = self | 
					
						
							|  |  |  |                     self.loggerDict[name] = rv | 
					
						
							|  |  |  |                     self._fixupChildren(ph, rv) | 
					
						
							|  |  |  |                     self._fixupParents(rv) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 rv = _loggerClass(name) | 
					
						
							|  |  |  |                 rv.manager = self | 
					
						
							|  |  |  |                 self.loggerDict[name] = rv | 
					
						
							|  |  |  |                 self._fixupParents(rv) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             _releaseLock() | 
					
						
							|  |  |  |         return rv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _fixupParents(self, alogger): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Ensure that there are either loggers or placeholders all the way | 
					
						
							|  |  |  |         from the specified logger to the root of the logger hierarchy. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         name = alogger.name | 
					
						
							|  |  |  |         i = string.rfind(name, ".") | 
					
						
							|  |  |  |         rv = None | 
					
						
							|  |  |  |         while (i > 0) and not rv: | 
					
						
							|  |  |  |             substr = name[:i] | 
					
						
							|  |  |  |             if not self.loggerDict.has_key(substr): | 
					
						
							|  |  |  |                 self.loggerDict[substr] = PlaceHolder(alogger) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 obj = self.loggerDict[substr] | 
					
						
							|  |  |  |                 if isinstance(obj, Logger): | 
					
						
							|  |  |  |                     rv = obj | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     assert isinstance(obj, PlaceHolder) | 
					
						
							|  |  |  |                     obj.append(alogger) | 
					
						
							|  |  |  |             i = string.rfind(name, ".", 0, i - 1) | 
					
						
							|  |  |  |         if not rv: | 
					
						
							|  |  |  |             rv = self.root | 
					
						
							|  |  |  |         alogger.parent = rv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _fixupChildren(self, ph, alogger): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Ensure that children of the placeholder ph are connected to the | 
					
						
							|  |  |  |         specified logger. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         for c in ph.loggers: | 
					
						
							|  |  |  |             if string.find(c.parent.name, alogger.name) <> 0: | 
					
						
							|  |  |  |                 alogger.parent = c.parent | 
					
						
							|  |  |  |                 c.parent = alogger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | #   Logger classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Logger(Filterer): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Instances of the Logger class represent a single logging channel. A | 
					
						
							|  |  |  |     "logging channel" indicates an area of an application. Exactly how an | 
					
						
							|  |  |  |     "area" is defined is up to the application developer. Since an | 
					
						
							|  |  |  |     application can have any number of areas, logging channels are identified | 
					
						
							|  |  |  |     by a unique string. Application areas can be nested (e.g. an area | 
					
						
							|  |  |  |     of "input processing" might include sub-areas "read CSV files", "read | 
					
						
							|  |  |  |     XLS files" and "read Gnumeric files"). To cater for this natural nesting, | 
					
						
							|  |  |  |     channel names are organized into a namespace hierarchy where levels are | 
					
						
							|  |  |  |     separated by periods, much like the Java or Python package namespace. So | 
					
						
							|  |  |  |     in the instance given above, channel names might be "input" for the upper | 
					
						
							|  |  |  |     level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. | 
					
						
							|  |  |  |     There is no arbitrary limit to the depth of nesting. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, name, level=NOTSET): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the logger with a name and an optional level. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Filterer.__init__(self) | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.level = level | 
					
						
							|  |  |  |         self.parent = None | 
					
						
							|  |  |  |         self.propagate = 1 | 
					
						
							|  |  |  |         self.handlers = [] | 
					
						
							|  |  |  |         self.disabled = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setLevel(self, level): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Set the logging level of this logger. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.level = level | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #   def getRoot(self): | 
					
						
							|  |  |  | #       """ | 
					
						
							|  |  |  | #       Get the root of the logger hierarchy. | 
					
						
							|  |  |  | #       """ | 
					
						
							|  |  |  | #       return Logger.root | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def debug(self, msg, *args, **kwargs): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Log 'msg % args' with severity 'DEBUG'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= DEBUG: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if DEBUG >= self.getEffectiveLevel(): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (DEBUG, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def info(self, msg, *args, **kwargs): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Log 'msg % args' with severity 'INFO'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.info("Houston, we have a %s", "interesting problem", exc_info=1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= INFO: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if INFO >= self.getEffectiveLevel(): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (INFO, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     def warning(self, msg, *args, **kwargs): | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         Log 'msg % args' with severity 'WARNING'. | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         if self.manager.disable >= WARNING: | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |             return | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |         if self.isEnabledFor(WARNING): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (WARNING, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     warn = warning | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def error(self, msg, *args, **kwargs): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Log 'msg % args' with severity 'ERROR'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.error("Houston, we have a %s", "major problem", exc_info=1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= ERROR: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if self.isEnabledFor(ERROR): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (ERROR, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def exception(self, msg, *args): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Convenience method for logging an ERROR with exception information. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |         apply(self.error, (msg,) + args, {'exc_info': 1}) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def critical(self, msg, *args, **kwargs): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Log 'msg % args' with severity 'CRITICAL'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.critical("Houston, we have a %s", "major disaster", exc_info=1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= CRITICAL: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if CRITICAL >= self.getEffectiveLevel(): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (CRITICAL, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     fatal = critical | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def log(self, level, msg, *args, **kwargs): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Log 'msg % args' with the severity 'level'. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         To pass exception information, use the keyword argument exc_info with | 
					
						
							|  |  |  |         a true value, e.g. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.log(level, "We have a %s", "mysterious problem", exc_info=1) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= level: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if self.isEnabledFor(level): | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |             apply(self._log, (level, msg, args), kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def findCaller(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Find the stack frame of the caller so that we can note the source | 
					
						
							|  |  |  |         file name and line number. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-01-23 18:29:29 +00:00
										 |  |  |         f = sys._getframe(1) | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             co = f.f_code | 
					
						
							|  |  |  |             filename = os.path.normcase(co.co_filename) | 
					
						
							|  |  |  |             if filename == _srcfile: | 
					
						
							|  |  |  |                 f = f.f_back | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             return filename, f.f_lineno | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def makeRecord(self, name, level, fn, lno, msg, args, exc_info): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         A factory method which can be overridden in subclasses to create | 
					
						
							|  |  |  |         specialized LogRecords. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return LogRecord(name, level, fn, lno, msg, args, exc_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _log(self, level, msg, args, exc_info=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Low-level logging routine which creates a LogRecord and then calls | 
					
						
							|  |  |  |         all the handlers of this logger to handle the record. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-01-23 18:29:29 +00:00
										 |  |  |         if _srcfile: | 
					
						
							|  |  |  |             fn, lno = self.findCaller() | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             fn, lno = "<unknown file>", 0 | 
					
						
							|  |  |  |         if exc_info: | 
					
						
							|  |  |  |             exc_info = sys.exc_info() | 
					
						
							|  |  |  |         record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info) | 
					
						
							|  |  |  |         self.handle(record) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def handle(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Call the handlers for the specified record. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This method is used for unpickled records received from a socket, as | 
					
						
							|  |  |  |         well as those created locally. Logger-level filtering is applied. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if (not self.disabled) and self.filter(record): | 
					
						
							|  |  |  |             self.callHandlers(record) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def addHandler(self, hdlr): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Add the specified handler to this logger. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if not (hdlr in self.handlers): | 
					
						
							|  |  |  |             self.handlers.append(hdlr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def removeHandler(self, hdlr): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Remove the specified handler from this logger. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if hdlr in self.handlers: | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |             #hdlr.close() | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |             self.handlers.remove(hdlr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def callHandlers(self, record): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Pass a record to all relevant handlers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Loop through all handlers for this logger and its parents in the | 
					
						
							|  |  |  |         logger hierarchy. If no handler was found, output a one-off error | 
					
						
							|  |  |  |         message to sys.stderr. Stop searching up the hierarchy whenever a | 
					
						
							|  |  |  |         logger with the "propagate" attribute set to zero is found - that | 
					
						
							|  |  |  |         will be the last logger whose handlers are called. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         c = self | 
					
						
							|  |  |  |         found = 0 | 
					
						
							|  |  |  |         while c: | 
					
						
							|  |  |  |             for hdlr in c.handlers: | 
					
						
							|  |  |  |                 found = found + 1 | 
					
						
							|  |  |  |                 if record.levelno >= hdlr.level: | 
					
						
							|  |  |  |                     hdlr.handle(record) | 
					
						
							|  |  |  |             if not c.propagate: | 
					
						
							|  |  |  |                 c = None    #break out | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 c = c.parent | 
					
						
							|  |  |  |         if (found == 0) and not self.manager.emittedNoHandlerWarning: | 
					
						
							|  |  |  |             sys.stderr.write("No handlers could be found for logger" | 
					
						
							|  |  |  |                              " \"%s\"\n" % self.name) | 
					
						
							|  |  |  |             self.manager.emittedNoHandlerWarning = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getEffectiveLevel(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Get the effective level for this logger. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Loop through this logger and its parents in the logger hierarchy, | 
					
						
							|  |  |  |         looking for a non-zero logging level. Return the first one found. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger = self | 
					
						
							|  |  |  |         while logger: | 
					
						
							|  |  |  |             if logger.level: | 
					
						
							|  |  |  |                 return logger.level | 
					
						
							|  |  |  |             logger = logger.parent | 
					
						
							|  |  |  |         return NOTSET | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def isEnabledFor(self, level): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Is this logger enabled for level 'level'? | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if self.manager.disable >= level: | 
					
						
							|  |  |  |             return 0 | 
					
						
							|  |  |  |         return level >= self.getEffectiveLevel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RootLogger(Logger): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     A root logger is not that different to any other logger, except that | 
					
						
							|  |  |  |     it must have a logging level and there is only one instance of it in | 
					
						
							|  |  |  |     the hierarchy. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def __init__(self, level): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the logger with the name "root". | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Logger.__init__(self, "root", level) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _loggerClass = Logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | root = RootLogger(WARNING) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | Logger.root = root | 
					
						
							|  |  |  | Logger.manager = Manager(Logger.root) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | # Configuration classes and functions | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def basicConfig(): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Do basic configuration for the logging system by creating a | 
					
						
							|  |  |  |     StreamHandler with a default Formatter and adding it to the | 
					
						
							|  |  |  |     root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         hdlr = StreamHandler() | 
					
						
							|  |  |  |         fmt = Formatter(BASIC_FORMAT) | 
					
						
							|  |  |  |         hdlr.setFormatter(fmt) | 
					
						
							|  |  |  |         root.addHandler(hdlr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | # Utility functions at module level. | 
					
						
							|  |  |  | # Basically delegate everything to the root logger. | 
					
						
							|  |  |  | #--------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def getLogger(name=None): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Return a logger with the specified name, creating it if necessary. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If no name is specified, return the root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if name: | 
					
						
							|  |  |  |         return Logger.manager.getLogger(name) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return root | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #def getRootLogger(): | 
					
						
							|  |  |  | #    """ | 
					
						
							|  |  |  | #    Return the root logger. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #    Note that getLogger('') now does the same thing, so this function is | 
					
						
							|  |  |  | #    deprecated and may disappear in the future. | 
					
						
							|  |  |  | #    """ | 
					
						
							|  |  |  | #    return root | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def critical(msg, *args, **kwargs): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Log a message with severity 'CRITICAL' on the root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         basicConfig() | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(root.critical, (msg,)+args, kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | fatal = critical | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def error(msg, *args, **kwargs): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Log a message with severity 'ERROR' on the root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         basicConfig() | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(root.error, (msg,)+args, kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def exception(msg, *args): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Log a message with severity 'ERROR' on the root logger, | 
					
						
							|  |  |  |     with exception information. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(error, (msg,)+args, {'exc_info': 1}) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | def warning(msg, *args, **kwargs): | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  |     Log a message with severity 'WARNING' on the root logger. | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         basicConfig() | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(root.warning, (msg,)+args, kwargs) | 
					
						
							| 
									
										
										
										
											2003-02-18 14:20:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | warn = warning | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def info(msg, *args, **kwargs): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Log a message with severity 'INFO' on the root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         basicConfig() | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(root.info, (msg,)+args, kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def debug(msg, *args, **kwargs): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Log a message with severity 'DEBUG' on the root logger. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if len(root.handlers) == 0: | 
					
						
							|  |  |  |         basicConfig() | 
					
						
							| 
									
										
										
										
											2003-03-02 20:47:29 +00:00
										 |  |  |     apply(root.debug, (msg,)+args, kwargs) | 
					
						
							| 
									
										
										
										
											2002-11-13 16:15:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def disable(level): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Disable all logging calls less severe than 'level'. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     root.manager.disable = level | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def shutdown(): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Perform any cleanup actions in the logging system (e.g. flushing | 
					
						
							|  |  |  |     buffers). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Should be called at application exit. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     for h in _handlers.keys(): | 
					
						
							|  |  |  |         h.flush() | 
					
						
							|  |  |  |         h.close() |