PyXR

c:\python24\lib \ logging

Subpackages:

Modules

Init code



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
SourceForge.net Logo