0001 # Copyright 2001-2004 by Vinay Sajip. All Rights Reserved. 0002 # 0003 # Permission to use, copy, modify, and distribute this software and its 0004 # documentation for any purpose and without fee is hereby granted, 0005 # provided that the above copyright notice appear in all copies and that 0006 # both that copyright notice and this permission notice appear in 0007 # supporting documentation, and that the name of Vinay Sajip 0008 # not be used in advertising or publicity pertaining to distribution 0009 # of the software without specific, written prior permission. 0010 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 0011 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 0012 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 0013 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 0014 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 0015 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 0016 0017 """ 0018 Logging package for Python. Based on PEP 282 and comments thereto in 0019 comp.lang.python, and influenced by Apache's log4j system. 0020 0021 Should work under Python versions >= 1.5.2, except that source line 0022 information is not available unless 'sys._getframe()' is. 0023 0024 Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved. 0025 0026 To use, simply 'import logging' and log away! 0027 """ 0028 0029 import sys, os, types, time, string, cStringIO 0030 0031 try: 0032 import thread 0033 import threading 0034 except ImportError: 0035 thread = None 0036 0037 __author__ = "Vinay Sajip <vinay_sajip@red-dove.com>" 0038 __status__ = "beta" 0039 __version__ = "0.4.9.6" 0040 __date__ = "20 October 2004" 0041 0042 #--------------------------------------------------------------------------- 0043 # Miscellaneous module data 0044 #--------------------------------------------------------------------------- 0045 0046 # 0047 #_srcfile is used when walking the stack to check when we've got the first 0048 # caller stack frame. 0049 # 0050 if string.lower(__file__[-4:]) in ['.pyc', '.pyo']: 0051 _srcfile = __file__[:-4] + '.py' 0052 else: 0053 _srcfile = __file__ 0054 _srcfile = os.path.normcase(_srcfile) 0055 0056 # _srcfile is only used in conjunction with sys._getframe(). 0057 # To provide compatibility with older versions of Python, set _srcfile 0058 # to None if _getframe() is not available; this value will prevent 0059 # findCaller() from being called. 0060 if not hasattr(sys, "_getframe"): 0061 _srcfile = None 0062 0063 # 0064 #_startTime is used as the base when calculating the relative time of events 0065 # 0066 _startTime = time.time() 0067 0068 # 0069 #raiseExceptions is used to see if exceptions during handling should be 0070 #propagated 0071 # 0072 raiseExceptions = 1 0073 0074 #--------------------------------------------------------------------------- 0075 # Level related stuff 0076 #--------------------------------------------------------------------------- 0077 # 0078 # Default levels and level names, these can be replaced with any positive set 0079 # of values having corresponding names. There is a pseudo-level, NOTSET, which 0080 # is only really there as a lower limit for user-defined levels. Handlers and 0081 # loggers are initialized with NOTSET so that they will log all messages, even 0082 # at user-defined levels. 0083 # 0084 CRITICAL = 50 0085 FATAL = CRITICAL 0086 ERROR = 40 0087 WARNING = 30 0088 WARN = WARNING 0089 INFO = 20 0090 DEBUG = 10 0091 NOTSET = 0 0092 0093 _levelNames = { 0094 CRITICAL : 'CRITICAL', 0095 ERROR : 'ERROR', 0096 WARNING : 'WARNING', 0097 INFO : 'INFO', 0098 DEBUG : 'DEBUG', 0099 NOTSET : 'NOTSET', 0100 'CRITICAL' : CRITICAL, 0101 'ERROR' : ERROR, 0102 'WARN' : WARNING, 0103 'WARNING' : WARNING, 0104 'INFO' : INFO, 0105 'DEBUG' : DEBUG, 0106 'NOTSET' : NOTSET, 0107 } 0108 0109 def getLevelName(level): 0110 """ 0111 Return the textual representation of logging level 'level'. 0112 0113 If the level is one of the predefined levels (CRITICAL, ERROR, WARNING, 0114 INFO, DEBUG) then you get the corresponding string. If you have 0115 associated levels with names using addLevelName then the name you have 0116 associated with 'level' is returned. 0117 0118 If a numeric value corresponding to one of the defined levels is passed 0119 in, the corresponding string representation is returned. 0120 0121 Otherwise, the string "Level %s" % level is returned. 0122 """ 0123 return _levelNames.get(level, ("Level %s" % level)) 0124 0125 def addLevelName(level, levelName): 0126 """ 0127 Associate 'levelName' with 'level'. 0128 0129 This is used when converting levels to text during message formatting. 0130 """ 0131 _acquireLock() 0132 try: #unlikely to cause an exception, but you never know... 0133 _levelNames[level] = levelName 0134 _levelNames[levelName] = level 0135 finally: 0136 _releaseLock() 0137 0138 #--------------------------------------------------------------------------- 0139 # Thread-related stuff 0140 #--------------------------------------------------------------------------- 0141 0142 # 0143 #_lock is used to serialize access to shared data structures in this module. 0144 #This needs to be an RLock because fileConfig() creates Handlers and so 0145 #might arbitrary user threads. Since Handler.__init__() updates the shared 0146 #dictionary _handlers, it needs to acquire the lock. But if configuring, 0147 #the lock would already have been acquired - so we need an RLock. 0148 #The same argument applies to Loggers and Manager.loggerDict. 0149 # 0150 _lock = None 0151 0152 def _acquireLock(): 0153 """ 0154 Acquire the module-level lock for serializing access to shared data. 0155 0156 This should be released with _releaseLock(). 0157 """ 0158 global _lock 0159 if (not _lock) and thread: 0160 _lock = threading.RLock() 0161 if _lock: 0162 _lock.acquire() 0163 0164 def _releaseLock(): 0165 """ 0166 Release the module-level lock acquired by calling _acquireLock(). 0167 """ 0168 if _lock: 0169 _lock.release() 0170 0171 #--------------------------------------------------------------------------- 0172 # The logging record 0173 #--------------------------------------------------------------------------- 0174 0175 class LogRecord: 0176 """ 0177 A LogRecord instance represents an event being logged. 0178 0179 LogRecord instances are created every time something is logged. They 0180 contain all the information pertinent to the event being logged. The 0181 main information passed in is in msg and args, which are combined 0182 using str(msg) % args to create the message field of the record. The 0183 record also includes information such as when the record was created, 0184 the source line where the logging call was made, and any exception 0185 information to be logged. 0186 """ 0187 def __init__(self, name, level, pathname, lineno, msg, args, exc_info): 0188 """ 0189 Initialize a logging record with interesting information. 0190 """ 0191 ct = time.time() 0192 self.name = name 0193 self.msg = msg 0194 # 0195 # The following statement allows passing of a dictionary as a sole 0196 # argument, so that you can do something like 0197 # logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2}) 0198 # Suggested by Stefan Behnel. 0199 # Note that without the test for args[0], we get a problem because 0200 # during formatting, we test to see if the arg is present using 0201 # 'if self.args:'. If the event being logged is e.g. 'Value is %d' 0202 # and if the passed arg fails 'if self.args:' then no formatting 0203 # is done. For example, logger.warn('Value is %d', 0) would log 0204 # 'Value is %d' instead of 'Value is 0'. 0205 # For the use case of passing a dictionary, this should not be a 0206 # problem. 0207 if args and (len(args) == 1) and args[0] and (type(args[0]) == types.DictType): 0208 args = args[0] 0209 self.args = args 0210 self.levelname = getLevelName(level) 0211 self.levelno = level 0212 self.pathname = pathname 0213 try: 0214 self.filename = os.path.basename(pathname) 0215 self.module = os.path.splitext(self.filename)[0] 0216 except: 0217 self.filename = pathname 0218 self.module = "Unknown module" 0219 self.exc_info = exc_info 0220 self.exc_text = None # used to cache the traceback text 0221 self.lineno = lineno 0222 self.created = ct 0223 self.msecs = (ct - long(ct)) * 1000 0224 self.relativeCreated = (self.created - _startTime) * 1000 0225 if thread: 0226 self.thread = thread.get_ident() 0227 else: 0228 self.thread = None 0229 if hasattr(os, 'getpid'): 0230 self.process = os.getpid() 0231 else: 0232 self.process = None 0233 0234 def __str__(self): 0235 return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno, 0236 self.pathname, self.lineno, self.msg) 0237 0238 def getMessage(self): 0239 """ 0240 Return the message for this LogRecord. 0241 0242 Return the message for this LogRecord after merging any user-supplied 0243 arguments with the message. 0244 """ 0245 if not hasattr(types, "UnicodeType"): #if no unicode support... 0246 msg = str(self.msg) 0247 else: 0248 try: 0249 msg = str(self.msg) 0250 except UnicodeError: 0251 msg = self.msg #Defer encoding till later 0252 if self.args: 0253 msg = msg % self.args 0254 return msg 0255 0256 def makeLogRecord(dict): 0257 """ 0258 Make a LogRecord whose attributes are defined by the specified dictionary, 0259 This function is useful for converting a logging event received over 0260 a socket connection (which is sent as a dictionary) into a LogRecord 0261 instance. 0262 """ 0263 rv = LogRecord(None, None, "", 0, "", (), None) 0264 rv.__dict__.update(dict) 0265 return rv 0266 0267 #--------------------------------------------------------------------------- 0268 # Formatter classes and functions 0269 #--------------------------------------------------------------------------- 0270 0271 class Formatter: 0272 """ 0273 Formatter instances are used to convert a LogRecord to text. 0274 0275 Formatters need to know how a LogRecord is constructed. They are 0276 responsible for converting a LogRecord to (usually) a string which can 0277 be interpreted by either a human or an external system. The base Formatter 0278 allows a formatting string to be specified. If none is supplied, the 0279 default value of "%s(message)\\n" is used. 0280 0281 The Formatter can be initialized with a format string which makes use of 0282 knowledge of the LogRecord attributes - e.g. the default value mentioned 0283 above makes use of the fact that the user's message and arguments are pre- 0284 formatted into a LogRecord's message attribute. Currently, the useful 0285 attributes in a LogRecord are described by: 0286 0287 %(name)s Name of the logger (logging channel) 0288 %(levelno)s Numeric logging level for the message (DEBUG, INFO, 0289 WARNING, ERROR, CRITICAL) 0290 %(levelname)s Text logging level for the message ("DEBUG", "INFO", 0291 "WARNING", "ERROR", "CRITICAL") 0292 %(pathname)s Full pathname of the source file where the logging 0293 call was issued (if available) 0294 %(filename)s Filename portion of pathname 0295 %(module)s Module (name portion of filename) 0296 %(lineno)d Source line number where the logging call was issued 0297 (if available) 0298 %(created)f Time when the LogRecord was created (time.time() 0299 return value) 0300 %(asctime)s Textual time when the LogRecord was created 0301 %(msecs)d Millisecond portion of the creation time 0302 %(relativeCreated)d Time in milliseconds when the LogRecord was created, 0303 relative to the time the logging module was loaded 0304 (typically at application startup time) 0305 %(thread)d Thread ID (if available) 0306 %(process)d Process ID (if available) 0307 %(message)s The result of record.getMessage(), computed just as 0308 the record is emitted 0309 """ 0310 0311 converter = time.localtime 0312 0313 def __init__(self, fmt=None, datefmt=None): 0314 """ 0315 Initialize the formatter with specified format strings. 0316 0317 Initialize the formatter either with the specified format string, or a 0318 default as described above. Allow for specialized date formatting with 0319 the optional datefmt argument (if omitted, you get the ISO8601 format). 0320 """ 0321 if fmt: 0322 self._fmt = fmt 0323 else: 0324 self._fmt = "%(message)s" 0325 self.datefmt = datefmt 0326 0327 def formatTime(self, record, datefmt=None): 0328 """ 0329 Return the creation time of the specified LogRecord as formatted text. 0330 0331 This method should be called from format() by a formatter which 0332 wants to make use of a formatted time. This method can be overridden 0333 in formatters to provide for any specific requirement, but the 0334 basic behaviour is as follows: if datefmt (a string) is specified, 0335 it is used with time.strftime() to format the creation time of the 0336 record. Otherwise, the ISO8601 format is used. The resulting 0337 string is returned. This function uses a user-configurable function 0338 to convert the creation time to a tuple. By default, time.localtime() 0339 is used; to change this for a particular formatter instance, set the 0340 'converter' attribute to a function with the same signature as 0341 time.localtime() or time.gmtime(). To change it for all formatters, 0342 for example if you want all logging times to be shown in GMT, 0343 set the 'converter' attribute in the Formatter class. 0344 """ 0345 ct = self.converter(record.created) 0346 if datefmt: 0347 s = time.strftime(datefmt, ct) 0348 else: 0349 t = time.strftime("%Y-%m-%d %H:%M:%S", ct) 0350 s = "%s,%03d" % (t, record.msecs) 0351 return s 0352 0353 def formatException(self, ei): 0354 """ 0355 Format and return the specified exception information as a string. 0356 0357 This default implementation just uses 0358 traceback.print_exception() 0359 """ 0360 import traceback 0361 sio = cStringIO.StringIO() 0362 traceback.print_exception(ei[0], ei[1], ei[2], None, sio) 0363 s = sio.getvalue() 0364 sio.close() 0365 if s[-1] == "\n": 0366 s = s[:-1] 0367 return s 0368 0369 def format(self, record): 0370 """ 0371 Format the specified record as text. 0372 0373 The record's attribute dictionary is used as the operand to a 0374 string formatting operation which yields the returned string. 0375 Before formatting the dictionary, a couple of preparatory steps 0376 are carried out. The message attribute of the record is computed 0377 using LogRecord.getMessage(). If the formatting string contains 0378 "%(asctime)", formatTime() is called to format the event time. 0379 If there is exception information, it is formatted using 0380 formatException() and appended to the message. 0381 """ 0382 record.message = record.getMessage() 0383 if string.find(self._fmt,"%(asctime)") >= 0: 0384 record.asctime = self.formatTime(record, self.datefmt) 0385 s = self._fmt % record.__dict__ 0386 if record.exc_info: 0387 # Cache the traceback text to avoid converting it multiple times 0388 # (it's constant anyway) 0389 if not record.exc_text: 0390 record.exc_text = self.formatException(record.exc_info) 0391 if record.exc_text: 0392 if s[-1] != "\n": 0393 s = s + "\n" 0394 s = s + record.exc_text 0395 return s 0396 0397 # 0398 # The default formatter to use when no other is specified 0399 # 0400 _defaultFormatter = Formatter() 0401 0402 class BufferingFormatter: 0403 """ 0404 A formatter suitable for formatting a number of records. 0405 """ 0406 def __init__(self, linefmt=None): 0407 """ 0408 Optionally specify a formatter which will be used to format each 0409 individual record. 0410 """ 0411 if linefmt: 0412 self.linefmt = linefmt 0413 else: 0414 self.linefmt = _defaultFormatter 0415 0416 def formatHeader(self, records): 0417 """ 0418 Return the header string for the specified records. 0419 """ 0420 return "" 0421 0422 def formatFooter(self, records): 0423 """ 0424 Return the footer string for the specified records. 0425 """ 0426 return "" 0427 0428 def format(self, records): 0429 """ 0430 Format the specified records and return the result as a string. 0431 """ 0432 rv = "" 0433 if len(records) > 0: 0434 rv = rv + self.formatHeader(records) 0435 for record in records: 0436 rv = rv + self.linefmt.format(record) 0437 rv = rv + self.formatFooter(records) 0438 return rv 0439 0440 #--------------------------------------------------------------------------- 0441 # Filter classes and functions 0442 #--------------------------------------------------------------------------- 0443 0444 class Filter: 0445 """ 0446 Filter instances are used to perform arbitrary filtering of LogRecords. 0447 0448 Loggers and Handlers can optionally use Filter instances to filter 0449 records as desired. The base filter class only allows events which are 0450 below a certain point in the logger hierarchy. For example, a filter 0451 initialized with "A.B" will allow events logged by loggers "A.B", 0452 "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If 0453 initialized with the empty string, all events are passed. 0454 """ 0455 def __init__(self, name=''): 0456 """ 0457 Initialize a filter. 0458 0459 Initialize with the name of the logger which, together with its 0460 children, will have its events allowed through the filter. If no 0461 name is specified, allow every event. 0462 """ 0463 self.name = name 0464 self.nlen = len(name) 0465 0466 def filter(self, record): 0467 """ 0468 Determine if the specified record is to be logged. 0469 0470 Is the specified record to be logged? Returns 0 for no, nonzero for 0471 yes. If deemed appropriate, the record may be modified in-place. 0472 """ 0473 if self.nlen == 0: 0474 return 1 0475 elif self.name == record.name: 0476 return 1 0477 elif string.find(record.name, self.name, 0, self.nlen) != 0: 0478 return 0 0479 return (record.name[self.nlen] == ".") 0480 0481 class Filterer: 0482 """ 0483 A base class for loggers and handlers which allows them to share 0484 common code. 0485 """ 0486 def __init__(self): 0487 """ 0488 Initialize the list of filters to be an empty list. 0489 """ 0490 self.filters = [] 0491 0492 def addFilter(self, filter): 0493 """ 0494 Add the specified filter to this handler. 0495 """ 0496 if not (filter in self.filters): 0497 self.filters.append(filter) 0498 0499 def removeFilter(self, filter): 0500 """ 0501 Remove the specified filter from this handler. 0502 """ 0503 if filter in self.filters: 0504 self.filters.remove(filter) 0505 0506 def filter(self, record): 0507 """ 0508 Determine if a record is loggable by consulting all the filters. 0509 0510 The default is to allow the record to be logged; any filter can veto 0511 this and the record is then dropped. Returns a zero value if a record 0512 is to be dropped, else non-zero. 0513 """ 0514 rv = 1 0515 for f in self.filters: 0516 if not f.filter(record): 0517 rv = 0 0518 break 0519 return rv 0520 0521 #--------------------------------------------------------------------------- 0522 # Handler classes and functions 0523 #--------------------------------------------------------------------------- 0524 0525 _handlers = {} #repository of handlers (for flushing when shutdown called) 0526 0527 class Handler(Filterer): 0528 """ 0529 Handler instances dispatch logging events to specific destinations. 0530 0531 The base handler class. Acts as a placeholder which defines the Handler 0532 interface. Handlers can optionally use Formatter instances to format 0533 records as desired. By default, no formatter is specified; in this case, 0534 the 'raw' message as determined by record.message is logged. 0535 """ 0536 def __init__(self, level=NOTSET): 0537 """ 0538 Initializes the instance - basically setting the formatter to None 0539 and the filter list to empty. 0540 """ 0541 Filterer.__init__(self) 0542 self.level = level 0543 self.formatter = None 0544 #get the module data lock, as we're updating a shared structure. 0545 _acquireLock() 0546 try: #unlikely to raise an exception, but you never know... 0547 _handlers[self] = 1 0548 finally: 0549 _releaseLock() 0550 self.createLock() 0551 0552 def createLock(self): 0553 """ 0554 Acquire a thread lock for serializing access to the underlying I/O. 0555 """ 0556 if thread: 0557 self.lock = thread.allocate_lock() 0558 else: 0559 self.lock = None 0560 0561 def acquire(self): 0562 """ 0563 Acquire the I/O thread lock. 0564 """ 0565 if self.lock: 0566 self.lock.acquire() 0567 0568 def release(self): 0569 """ 0570 Release the I/O thread lock. 0571 """ 0572 if self.lock: 0573 self.lock.release() 0574 0575 def setLevel(self, level): 0576 """ 0577 Set the logging level of this handler. 0578 """ 0579 self.level = level 0580 0581 def format(self, record): 0582 """ 0583 Format the specified record. 0584 0585 If a formatter is set, use it. Otherwise, use the default formatter 0586 for the module. 0587 """ 0588 if self.formatter: 0589 fmt = self.formatter 0590 else: 0591 fmt = _defaultFormatter 0592 return fmt.format(record) 0593 0594 def emit(self, record): 0595 """ 0596 Do whatever it takes to actually log the specified logging record. 0597 0598 This version is intended to be implemented by subclasses and so 0599 raises a NotImplementedError. 0600 """ 0601 raise NotImplementedError, 'emit must be implemented '\ 0602 'by Handler subclasses' 0603 0604 def handle(self, record): 0605 """ 0606 Conditionally emit the specified logging record. 0607 0608 Emission depends on filters which may have been added to the handler. 0609 Wrap the actual emission of the record with acquisition/release of 0610 the I/O thread lock. Returns whether the filter passed the record for 0611 emission. 0612 """ 0613 rv = self.filter(record) 0614 if rv: 0615 self.acquire() 0616 try: 0617 self.emit(record) 0618 finally: 0619 self.release() 0620 return rv 0621 0622 def setFormatter(self, fmt): 0623 """ 0624 Set the formatter for this handler. 0625 """ 0626 self.formatter = fmt 0627 0628 def flush(self): 0629 """ 0630 Ensure all logging output has been flushed. 0631 0632 This version does nothing and is intended to be implemented by 0633 subclasses. 0634 """ 0635 pass 0636 0637 def close(self): 0638 """ 0639 Tidy up any resources used by the handler. 0640 0641 This version does removes the handler from an internal list 0642 of handlers which is closed when shutdown() is called. Subclasses 0643 should ensure that this gets called from overridden close() 0644 methods. 0645 """ 0646 #get the module data lock, as we're updating a shared structure. 0647 _acquireLock() 0648 try: #unlikely to raise an exception, but you never know... 0649 del _handlers[self] 0650 finally: 0651 _releaseLock() 0652 0653 def handleError(self, record): 0654 """ 0655 Handle errors which occur during an emit() call. 0656 0657 This method should be called from handlers when an exception is 0658 encountered during an emit() call. If raiseExceptions is false, 0659 exceptions get silently ignored. This is what is mostly wanted 0660 for a logging system - most users will not care about errors in 0661 the logging system, they are more interested in application errors. 0662 You could, however, replace this with a custom handler if you wish. 0663 The record which was being processed is passed in to this method. 0664 """ 0665 if raiseExceptions: 0666 import traceback 0667 ei = sys.exc_info() 0668 traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) 0669 del ei 0670 0671 class StreamHandler(Handler): 0672 """ 0673 A handler class which writes logging records, appropriately formatted, 0674 to a stream. Note that this class does not close the stream, as 0675 sys.stdout or sys.stderr may be used. 0676 """ 0677 def __init__(self, strm=None): 0678 """ 0679 Initialize the handler. 0680 0681 If strm is not specified, sys.stderr is used. 0682 """ 0683 Handler.__init__(self) 0684 if not strm: 0685 strm = sys.stderr 0686 self.stream = strm 0687 self.formatter = None 0688 0689 def flush(self): 0690 """ 0691 Flushes the stream. 0692 """ 0693 self.stream.flush() 0694 0695 def emit(self, record): 0696 """ 0697 Emit a record. 0698 0699 If a formatter is specified, it is used to format the record. 0700 The record is then written to the stream with a trailing newline 0701 [N.B. this may be removed depending on feedback]. If exception 0702 information is present, it is formatted using 0703 traceback.print_exception and appended to the stream. 0704 """ 0705 try: 0706 msg = self.format(record) 0707 fs = "%s\n" 0708 if not hasattr(types, "UnicodeType"): #if no unicode support... 0709 self.stream.write(fs % msg) 0710 else: 0711 try: 0712 self.stream.write(fs % msg) 0713 except UnicodeError: 0714 self.stream.write(fs % msg.encode("UTF-8")) 0715 self.flush() 0716 except: 0717 self.handleError(record) 0718 0719 class FileHandler(StreamHandler): 0720 """ 0721 A handler class which writes formatted logging records to disk files. 0722 """ 0723 def __init__(self, filename, mode="a"): 0724 """ 0725 Open the specified file and use it as the stream for logging. 0726 """ 0727 StreamHandler.__init__(self, open(filename, mode)) 0728 #keep the absolute path, otherwise derived classes which use this 0729 #may come a cropper when the current directory changes 0730 self.baseFilename = os.path.abspath(filename) 0731 self.mode = mode 0732 0733 def close(self): 0734 """ 0735 Closes the stream. 0736 """ 0737 self.flush() 0738 self.stream.close() 0739 StreamHandler.close(self) 0740 0741 #--------------------------------------------------------------------------- 0742 # Manager classes and functions 0743 #--------------------------------------------------------------------------- 0744 0745 class PlaceHolder: 0746 """ 0747 PlaceHolder instances are used in the Manager logger hierarchy to take 0748 the place of nodes for which no loggers have been defined. This class is 0749 intended for internal use only and not as part of the public API. 0750 """ 0751 def __init__(self, alogger): 0752 """ 0753 Initialize with the specified logger being a child of this placeholder. 0754 """ 0755 self.loggers = [alogger] 0756 0757 def append(self, alogger): 0758 """ 0759 Add the specified logger as a child of this placeholder. 0760 """ 0761 if alogger not in self.loggers: 0762 self.loggers.append(alogger) 0763 0764 # 0765 # Determine which class to use when instantiating loggers. 0766 # 0767 _loggerClass = None 0768 0769 def setLoggerClass(klass): 0770 """ 0771 Set the class to be used when instantiating a logger. The class should 0772 define __init__() such that only a name argument is required, and the 0773 __init__() should call Logger.__init__() 0774 """ 0775 if klass != Logger: 0776 if not issubclass(klass, Logger): 0777 raise TypeError, "logger not derived from logging.Logger: " + \ 0778 klass.__name__ 0779 global _loggerClass 0780 _loggerClass = klass 0781 0782 def getLoggerClass(): 0783 """ 0784 Return the class to be used when instantiating a logger. 0785 """ 0786 0787 return _loggerClass 0788 0789 class Manager: 0790 """ 0791 There is [under normal circumstances] just one Manager instance, which 0792 holds the hierarchy of loggers. 0793 """ 0794 def __init__(self, rootnode): 0795 """ 0796 Initialize the manager with the root node of the logger hierarchy. 0797 """ 0798 self.root = rootnode 0799 self.disable = 0 0800 self.emittedNoHandlerWarning = 0 0801 self.loggerDict = {} 0802 0803 def getLogger(self, name): 0804 """ 0805 Get a logger with the specified name (channel name), creating it 0806 if it doesn't yet exist. This name is a dot-separated hierarchical 0807 name, such as "a", "a.b", "a.b.c" or similar. 0808 0809 If a PlaceHolder existed for the specified name [i.e. the logger 0810 didn't exist but a child of it did], replace it with the created 0811 logger and fix up the parent/child references which pointed to the 0812 placeholder to now point to the logger. 0813 """ 0814 rv = None 0815 _acquireLock() 0816 try: 0817 if self.loggerDict.has_key(name): 0818 rv = self.loggerDict[name] 0819 if isinstance(rv, PlaceHolder): 0820 ph = rv 0821 rv = _loggerClass(name) 0822 rv.manager = self 0823 self.loggerDict[name] = rv 0824 self._fixupChildren(ph, rv) 0825 self._fixupParents(rv) 0826 else: 0827 rv = _loggerClass(name) 0828 rv.manager = self 0829 self.loggerDict[name] = rv 0830 self._fixupParents(rv) 0831 finally: 0832 _releaseLock() 0833 return rv 0834 0835 def _fixupParents(self, alogger): 0836 """ 0837 Ensure that there are either loggers or placeholders all the way 0838 from the specified logger to the root of the logger hierarchy. 0839 """ 0840 name = alogger.name 0841 i = string.rfind(name, ".") 0842 rv = None 0843 while (i > 0) and not rv: 0844 substr = name[:i] 0845 if not self.loggerDict.has_key(substr): 0846 self.loggerDict[substr] = PlaceHolder(alogger) 0847 else: 0848 obj = self.loggerDict[substr] 0849 if isinstance(obj, Logger): 0850 rv = obj 0851 else: 0852 assert isinstance(obj, PlaceHolder) 0853 obj.append(alogger) 0854 i = string.rfind(name, ".", 0, i - 1) 0855 if not rv: 0856 rv = self.root 0857 alogger.parent = rv 0858 0859 def _fixupChildren(self, ph, alogger): 0860 """ 0861 Ensure that children of the placeholder ph are connected to the 0862 specified logger. 0863 """ 0864 for c in ph.loggers: 0865 if string.find(c.parent.name, alogger.name) <> 0: 0866 alogger.parent = c.parent 0867 c.parent = alogger 0868 0869 #--------------------------------------------------------------------------- 0870 # Logger classes and functions 0871 #--------------------------------------------------------------------------- 0872 0873 class Logger(Filterer): 0874 """ 0875 Instances of the Logger class represent a single logging channel. A 0876 "logging channel" indicates an area of an application. Exactly how an 0877 "area" is defined is up to the application developer. Since an 0878 application can have any number of areas, logging channels are identified 0879 by a unique string. Application areas can be nested (e.g. an area 0880 of "input processing" might include sub-areas "read CSV files", "read 0881 XLS files" and "read Gnumeric files"). To cater for this natural nesting, 0882 channel names are organized into a namespace hierarchy where levels are 0883 separated by periods, much like the Java or Python package namespace. So 0884 in the instance given above, channel names might be "input" for the upper 0885 level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. 0886 There is no arbitrary limit to the depth of nesting. 0887 """ 0888 def __init__(self, name, level=NOTSET): 0889 """ 0890 Initialize the logger with a name and an optional level. 0891 """ 0892 Filterer.__init__(self) 0893 self.name = name 0894 self.level = level 0895 self.parent = None 0896 self.propagate = 1 0897 self.handlers = [] 0898 self.disabled = 0 0899 0900 def setLevel(self, level): 0901 """ 0902 Set the logging level of this logger. 0903 """ 0904 self.level = level 0905 0906 def debug(self, msg, *args, **kwargs): 0907 """ 0908 Log 'msg % args' with severity 'DEBUG'. 0909 0910 To pass exception information, use the keyword argument exc_info with 0911 a true value, e.g. 0912 0913 logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) 0914 """ 0915 if self.manager.disable >= DEBUG: 0916 return 0917 if DEBUG >= self.getEffectiveLevel(): 0918 apply(self._log, (DEBUG, msg, args), kwargs) 0919 0920 def info(self, msg, *args, **kwargs): 0921 """ 0922 Log 'msg % args' with severity 'INFO'. 0923 0924 To pass exception information, use the keyword argument exc_info with 0925 a true value, e.g. 0926 0927 logger.info("Houston, we have a %s", "interesting problem", exc_info=1) 0928 """ 0929 if self.manager.disable >= INFO: 0930 return 0931 if INFO >= self.getEffectiveLevel(): 0932 apply(self._log, (INFO, msg, args), kwargs) 0933 0934 def warning(self, msg, *args, **kwargs): 0935 """ 0936 Log 'msg % args' with severity 'WARNING'. 0937 0938 To pass exception information, use the keyword argument exc_info with 0939 a true value, e.g. 0940 0941 logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1) 0942 """ 0943 if self.manager.disable >= WARNING: 0944 return 0945 if self.isEnabledFor(WARNING): 0946 apply(self._log, (WARNING, msg, args), kwargs) 0947 0948 warn = warning 0949 0950 def error(self, msg, *args, **kwargs): 0951 """ 0952 Log 'msg % args' with severity 'ERROR'. 0953 0954 To pass exception information, use the keyword argument exc_info with 0955 a true value, e.g. 0956 0957 logger.error("Houston, we have a %s", "major problem", exc_info=1) 0958 """ 0959 if self.manager.disable >= ERROR: 0960 return 0961 if self.isEnabledFor(ERROR): 0962 apply(self._log, (ERROR, msg, args), kwargs) 0963 0964 def exception(self, msg, *args): 0965 """ 0966 Convenience method for logging an ERROR with exception information. 0967 """ 0968 apply(self.error, (msg,) + args, {'exc_info': 1}) 0969 0970 def critical(self, msg, *args, **kwargs): 0971 """ 0972 Log 'msg % args' with severity 'CRITICAL'. 0973 0974 To pass exception information, use the keyword argument exc_info with 0975 a true value, e.g. 0976 0977 logger.critical("Houston, we have a %s", "major disaster", exc_info=1) 0978 """ 0979 if self.manager.disable >= CRITICAL: 0980 return 0981 if CRITICAL >= self.getEffectiveLevel(): 0982 apply(self._log, (CRITICAL, msg, args), kwargs) 0983 0984 fatal = critical 0985 0986 def log(self, level, msg, *args, **kwargs): 0987 """ 0988 Log 'msg % args' with the integer severity 'level'. 0989 0990 To pass exception information, use the keyword argument exc_info with 0991 a true value, e.g. 0992 0993 logger.log(level, "We have a %s", "mysterious problem", exc_info=1) 0994 """ 0995 if type(level) != types.IntType: 0996 if raiseExceptions: 0997 raise TypeError, "level must be an integer" 0998 else: 0999 return 1000 if self.manager.disable >= level: 1001 return 1002 if self.isEnabledFor(level): 1003 apply(self._log, (level, msg, args), kwargs) 1004 1005 def findCaller(self): 1006 """ 1007 Find the stack frame of the caller so that we can note the source 1008 file name and line number. 1009 """ 1010 f = sys._getframe(1) 1011 while 1: 1012 co = f.f_code 1013 filename = os.path.normcase(co.co_filename) 1014 if filename == _srcfile: 1015 f = f.f_back 1016 continue 1017 return filename, f.f_lineno 1018 1019 def makeRecord(self, name, level, fn, lno, msg, args, exc_info): 1020 """ 1021 A factory method which can be overridden in subclasses to create 1022 specialized LogRecords. 1023 """ 1024 return LogRecord(name, level, fn, lno, msg, args, exc_info) 1025 1026 def _log(self, level, msg, args, exc_info=None): 1027 """ 1028 Low-level logging routine which creates a LogRecord and then calls 1029 all the handlers of this logger to handle the record. 1030 """ 1031 if _srcfile: 1032 fn, lno = self.findCaller() 1033 else: 1034 fn, lno = "<unknown file>", 0 1035 if exc_info: 1036 if type(exc_info) != types.TupleType: 1037 exc_info = sys.exc_info() 1038 record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info) 1039 self.handle(record) 1040 1041 def handle(self, record): 1042 """ 1043 Call the handlers for the specified record. 1044 1045 This method is used for unpickled records received from a socket, as 1046 well as those created locally. Logger-level filtering is applied. 1047 """ 1048 if (not self.disabled) and self.filter(record): 1049 self.callHandlers(record) 1050 1051 def addHandler(self, hdlr): 1052 """ 1053 Add the specified handler to this logger. 1054 """ 1055 if not (hdlr in self.handlers): 1056 self.handlers.append(hdlr) 1057 1058 def removeHandler(self, hdlr): 1059 """ 1060 Remove the specified handler from this logger. 1061 """ 1062 if hdlr in self.handlers: 1063 #hdlr.close() 1064 self.handlers.remove(hdlr) 1065 1066 def callHandlers(self, record): 1067 """ 1068 Pass a record to all relevant handlers. 1069 1070 Loop through all handlers for this logger and its parents in the 1071 logger hierarchy. If no handler was found, output a one-off error 1072 message to sys.stderr. Stop searching up the hierarchy whenever a 1073 logger with the "propagate" attribute set to zero is found - that 1074 will be the last logger whose handlers are called. 1075 """ 1076 c = self 1077 found = 0 1078 while c: 1079 for hdlr in c.handlers: 1080 found = found + 1 1081 if record.levelno >= hdlr.level: 1082 hdlr.handle(record) 1083 if not c.propagate: 1084 c = None #break out 1085 else: 1086 c = c.parent 1087 if (found == 0) and not self.manager.emittedNoHandlerWarning: 1088 sys.stderr.write("No handlers could be found for logger" 1089 " \"%s\"\n" % self.name) 1090 self.manager.emittedNoHandlerWarning = 1 1091 1092 def getEffectiveLevel(self): 1093 """ 1094 Get the effective level for this logger. 1095 1096 Loop through this logger and its parents in the logger hierarchy, 1097 looking for a non-zero logging level. Return the first one found. 1098 """ 1099 logger = self 1100 while logger: 1101 if logger.level: 1102 return logger.level 1103 logger = logger.parent 1104 return NOTSET 1105 1106 def isEnabledFor(self, level): 1107 """ 1108 Is this logger enabled for level 'level'? 1109 """ 1110 if self.manager.disable >= level: 1111 return 0 1112 return level >= self.getEffectiveLevel() 1113 1114 class RootLogger(Logger): 1115 """ 1116 A root logger is not that different to any other logger, except that 1117 it must have a logging level and there is only one instance of it in 1118 the hierarchy. 1119 """ 1120 def __init__(self, level): 1121 """ 1122 Initialize the logger with the name "root". 1123 """ 1124 Logger.__init__(self, "root", level) 1125 1126 _loggerClass = Logger 1127 1128 root = RootLogger(WARNING) 1129 Logger.root = root 1130 Logger.manager = Manager(Logger.root) 1131 1132 #--------------------------------------------------------------------------- 1133 # Configuration classes and functions 1134 #--------------------------------------------------------------------------- 1135 1136 BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" 1137 1138 def basicConfig(**kwargs): 1139 """ 1140 Do basic configuration for the logging system. 1141 1142 This function does nothing if the root logger already has handlers 1143 configured. It is a convenience method intended for use by simple scripts 1144 to do one-shot configuration of the logging package. 1145 1146 The default behaviour is to create a StreamHandler which writes to 1147 sys.stderr, set a formatter using the BASIC_FORMAT format string, and 1148 add the handler to the root logger. 1149 1150 A number of optional keyword arguments may be specified, which can alter 1151 the default behaviour. 1152 1153 filename Specifies that a FileHandler be created, using the specified 1154 filename, rather than a StreamHandler. 1155 filemode Specifies the mode to open the file, if filename is specified 1156 (if filemode is unspecified, it defaults to "a"). 1157 format Use the specified format string for the handler. 1158 datefmt Use the specified date/time format. 1159 level Set the root logger level to the specified level. 1160 stream Use the specified stream to initialize the StreamHandler. Note 1161 that this argument is incompatible with 'filename' - if both 1162 are present, 'stream' is ignored. 1163 1164 Note that you could specify a stream created using open(filename, mode) 1165 rather than passing the filename and mode in. However, it should be 1166 remembered that StreamHandler does not close its stream (since it may be 1167 using sys.stdout or sys.stderr), whereas FileHandler closes its stream 1168 when the handler is closed. 1169 """ 1170 if len(root.handlers) == 0: 1171 filename = kwargs.get("filename") 1172 if filename: 1173 mode = kwargs.get("filemode", "a") 1174 hdlr = FileHandler(filename, mode) 1175 else: 1176 stream = kwargs.get("stream") 1177 hdlr = StreamHandler(stream) 1178 fs = kwargs.get("format", BASIC_FORMAT) 1179 dfs = kwargs.get("datefmt", None) 1180 fmt = Formatter(fs, dfs) 1181 hdlr.setFormatter(fmt) 1182 root.addHandler(hdlr) 1183 level = kwargs.get("level") 1184 if level: 1185 root.setLevel(level) 1186 1187 #--------------------------------------------------------------------------- 1188 # Utility functions at module level. 1189 # Basically delegate everything to the root logger. 1190 #--------------------------------------------------------------------------- 1191 1192 def getLogger(name=None): 1193 """ 1194 Return a logger with the specified name, creating it if necessary. 1195 1196 If no name is specified, return the root logger. 1197 """ 1198 if name: 1199 return Logger.manager.getLogger(name) 1200 else: 1201 return root 1202 1203 #def getRootLogger(): 1204 # """ 1205 # Return the root logger. 1206 # 1207 # Note that getLogger('') now does the same thing, so this function is 1208 # deprecated and may disappear in the future. 1209 # """ 1210 # return root 1211 1212 def critical(msg, *args, **kwargs): 1213 """ 1214 Log a message with severity 'CRITICAL' on the root logger. 1215 """ 1216 if len(root.handlers) == 0: 1217 basicConfig() 1218 apply(root.critical, (msg,)+args, kwargs) 1219 1220 fatal = critical 1221 1222 def error(msg, *args, **kwargs): 1223 """ 1224 Log a message with severity 'ERROR' on the root logger. 1225 """ 1226 if len(root.handlers) == 0: 1227 basicConfig() 1228 apply(root.error, (msg,)+args, kwargs) 1229 1230 def exception(msg, *args): 1231 """ 1232 Log a message with severity 'ERROR' on the root logger, 1233 with exception information. 1234 """ 1235 apply(error, (msg,)+args, {'exc_info': 1}) 1236 1237 def warning(msg, *args, **kwargs): 1238 """ 1239 Log a message with severity 'WARNING' on the root logger. 1240 """ 1241 if len(root.handlers) == 0: 1242 basicConfig() 1243 apply(root.warning, (msg,)+args, kwargs) 1244 1245 warn = warning 1246 1247 def info(msg, *args, **kwargs): 1248 """ 1249 Log a message with severity 'INFO' on the root logger. 1250 """ 1251 if len(root.handlers) == 0: 1252 basicConfig() 1253 apply(root.info, (msg,)+args, kwargs) 1254 1255 def debug(msg, *args, **kwargs): 1256 """ 1257 Log a message with severity 'DEBUG' on the root logger. 1258 """ 1259 if len(root.handlers) == 0: 1260 basicConfig() 1261 apply(root.debug, (msg,)+args, kwargs) 1262 1263 def log(level, msg, *args, **kwargs): 1264 """ 1265 Log 'msg % args' with the integer severity 'level' on the root logger. 1266 """ 1267 if len(root.handlers) == 0: 1268 basicConfig() 1269 apply(root.log, (level, msg)+args, kwargs) 1270 1271 def disable(level): 1272 """ 1273 Disable all logging calls less severe than 'level'. 1274 """ 1275 root.manager.disable = level 1276 1277 def shutdown(): 1278 """ 1279 Perform any cleanup actions in the logging system (e.g. flushing 1280 buffers). 1281 1282 Should be called at application exit. 1283 """ 1284 for h in _handlers.keys(): 1285 #errors might occur, for example, if files are locked 1286 #we just ignore them 1287 try: 1288 h.flush() 1289 h.close() 1290 except: 1291 pass 1292 1293 #Let's try and shutdown automatically on application exit... 1294 try: 1295 import atexit 1296 atexit.register(shutdown) 1297 except ImportError: # for Python versions < 2.0 1298 def exithook(status, old_exit=sys.exit): 1299 try: 1300 shutdown() 1301 finally: 1302 old_exit(status) 1303 1304 sys.exit = exithook 1305
Generated by PyXR 0.9.4