Package logging
[hide private]
[frames] | no frames]

Source Code for Package logging

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