Package Ganga :: Package Utility :: Package external :: Package logging
[hide private]
[frames] | no frames]

Source Code for Package Ganga.Utility.external.logging

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