1372 lines · 46.0 KB · Python
RawDownload
# Copyright 2001-2007 by Vinay Sajip. All Rights Reserved.## Permission to use, copy, modify, and distribute this software and its# documentation for any purpose and without fee is hereby granted,# provided that the above copyright notice appear in all copies and that# both that copyright notice and this permission notice appear in# supporting documentation, and that the name of Vinay Sajip# not be used in advertising or publicity pertaining to distribution# of the software without specific, written prior permission.# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """Logging package for Python. Based on PEP 282 and comments thereto incomp.lang.python, and influenced by Apache's log4j system. Should work under Python versions >= 1.5.2, except that source lineinformation is not available unless 'sys._getframe()' is. Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved. To use, simply 'import logging' and log away!""" import sys, os, types, time, string, cStringIO, traceback try:    import codecsexcept ImportError:    codecs = None try:    import thread    import threadingexcept ImportError:    thread = None __author__  = "Vinay Sajip <vinay_sajip@red-dove.com>"__status__  = "production"__version__ = "0.5.0.2"__date__    = "16 February 2007" #---------------------------------------------------------------------------#   Miscellaneous module data#--------------------------------------------------------------------------- ## _srcfile is used when walking the stack to check when we've got the first# caller stack frame.#if hasattr(sys, 'frozen'): #support for py2exe    _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])elif string.lower(__file__[-4:]) in ['.pyc', '.pyo']:    _srcfile = __file__[:-4] + '.py'else:    _srcfile = __file___srcfile = os.path.normcase(_srcfile) # next bit filched from 1.5.2's inspect.pydef currentframe():    """Return the frame object for the caller's stack frame."""    try:        raise Exception    except:        return sys.exc_traceback.tb_frame.f_back if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)# done filching # _srcfile is only used in conjunction with sys._getframe().# To provide compatibility with older versions of Python, set _srcfile# to None if _getframe() is not available; this value will prevent# findCaller() from being called.#if not hasattr(sys, "_getframe"):#    _srcfile = None ##_startTime is used as the base when calculating the relative time of events#_startTime = time.time() ##raiseExceptions is used to see if exceptions during handling should be#propagated#raiseExceptions = 1 ## If you don't want threading information in the log, set this to zero#logThreads = 1 ## If you don't want process information in the log, set this to zero#logProcesses = 1 #---------------------------------------------------------------------------#   Level related stuff#---------------------------------------------------------------------------## Default levels and level names, these can be replaced with any positive set# of values having corresponding names. There is a pseudo-level, NOTSET, which# is only really there as a lower limit for user-defined levels. Handlers and# loggers are initialized with NOTSET so that they will log all messages, even# at user-defined levels.# CRITICAL = 50FATAL = CRITICALERROR = 40WARNING = 30WARN = WARNINGINFO = 20DEBUG = 10NOTSET = 0 _levelNames = {    CRITICAL : 'CRITICAL',    ERROR : 'ERROR',    WARNING : 'WARNING',    INFO : 'INFO',    DEBUG : 'DEBUG',    NOTSET : 'NOTSET',    'CRITICAL' : CRITICAL,    'ERROR' : ERROR,    'WARN' : WARNING,    'WARNING' : WARNING,    'INFO' : INFO,    'DEBUG' : DEBUG,    'NOTSET' : NOTSET,} def getLevelName(level):    """    Return the textual representation of logging level 'level'.     If the level is one of the predefined levels (CRITICAL, ERROR, WARNING,    INFO, DEBUG) then you get the corresponding string. If you have    associated levels with names using addLevelName then the name you have    associated with 'level' is returned.     If a numeric value corresponding to one of the defined levels is passed    in, the corresponding string representation is returned.     Otherwise, the string "Level %s" % level is returned.    """    return _levelNames.get(level, ("Level %s" % level)) def addLevelName(level, levelName):    """    Associate 'levelName' with 'level'.     This is used when converting levels to text during message formatting.    """    _acquireLock()    try:    #unlikely to cause an exception, but you never know...        _levelNames[level] = levelName        _levelNames[levelName] = level    finally:        _releaseLock() #---------------------------------------------------------------------------#   Thread-related stuff#--------------------------------------------------------------------------- ##_lock is used to serialize access to shared data structures in this module.#This needs to be an RLock because fileConfig() creates Handlers and so#might arbitrary user threads. Since Handler.__init__() updates the shared#dictionary _handlers, it needs to acquire the lock. But if configuring,#the lock would already have been acquired - so we need an RLock.#The same argument applies to Loggers and Manager.loggerDict.#_lock = None def _acquireLock():    """    Acquire the module-level lock for serializing access to shared data.     This should be released with _releaseLock().    """    global _lock    if (not _lock) and thread:        _lock = threading.RLock()    if _lock:        _lock.acquire() def _releaseLock():    """    Release the module-level lock acquired by calling _acquireLock().    """    if _lock:        _lock.release() #---------------------------------------------------------------------------#   The logging record#--------------------------------------------------------------------------- class LogRecord:    """    A LogRecord instance represents an event being logged.     LogRecord instances are created every time something is logged. They    contain all the information pertinent to the event being logged. The    main information passed in is in msg and args, which are combined    using str(msg) % args to create the message field of the record. The    record also includes information such as when the record was created,    the source line where the logging call was made, and any exception    information to be logged.    """    def __init__(self, name, level, pathname, lineno,                 msg, args, exc_info, func=None):        """        Initialize a logging record with interesting information.        """        ct = time.time()        self.name = name        self.msg = msg        #        # The following statement allows passing of a dictionary as a sole        # argument, so that you can do something like        #  logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2})        # Suggested by Stefan Behnel.        # Note that without the test for args[0], we get a problem because        # during formatting, we test to see if the arg is present using        # 'if self.args:'. If the event being logged is e.g. 'Value is %d'        # and if the passed arg fails 'if self.args:' then no formatting        # is done. For example, logger.warn('Value is %d', 0) would log        # 'Value is %d' instead of 'Value is 0'.        # For the use case of passing a dictionary, this should not be a        # problem.        if args and (len(args) == 1) and args[0] and (type(args[0]) == types.DictType):            args = args[0]        self.args = args        self.levelname = getLevelName(level)        self.levelno = level        self.pathname = pathname        try:            self.filename = os.path.basename(pathname)            self.module = os.path.splitext(self.filename)[0]        except:            self.filename = pathname            self.module = "Unknown module"        self.exc_info = exc_info        self.exc_text = None      # used to cache the traceback text        self.lineno = lineno        self.funcName = func        self.created = ct        self.msecs = (ct - long(ct)) * 1000        self.relativeCreated = (self.created - _startTime) * 1000        if logThreads and thread:            self.thread = thread.get_ident()            self.threadName = threading.currentThread().getName()        else:            self.thread = None            self.threadName = None        if logProcesses and hasattr(os, 'getpid'):            self.process = os.getpid()        else:            self.process = None     def __str__(self):        return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,            self.pathname, self.lineno, self.msg)     def getMessage(self):        """        Return the message for this LogRecord.         Return the message for this LogRecord after merging any user-supplied        arguments with the message.        """        if not hasattr(types, "UnicodeType"): #if no unicode support...            msg = str(self.msg)        else:            msg = self.msg            if type(msg) not in (types.UnicodeType, types.StringType):                try:                    msg = str(self.msg)                except UnicodeError:                    msg = self.msg      #Defer encoding till later        if self.args:            msg = msg % self.args        return msg def makeLogRecord(dict):    """    Make a LogRecord whose attributes are defined by the specified dictionary,    This function is useful for converting a logging event received over    a socket connection (which is sent as a dictionary) into a LogRecord    instance.    """    rv = LogRecord(None, None, "", 0, "", (), None, None)    rv.__dict__.update(dict)    return rv #---------------------------------------------------------------------------#   Formatter classes and functions#--------------------------------------------------------------------------- class Formatter:    """    Formatter instances are used to convert a LogRecord to text.     Formatters need to know how a LogRecord is constructed. They are    responsible for converting a LogRecord to (usually) a string which can    be interpreted by either a human or an external system. The base Formatter    allows a formatting string to be specified. If none is supplied, the    default value of "%s(message)\\n" is used.     The Formatter can be initialized with a format string which makes use of    knowledge of the LogRecord attributes - e.g. the default value mentioned    above makes use of the fact that the user's message and arguments are pre-    formatted into a LogRecord's message attribute. Currently, the useful    attributes in a LogRecord are described by:     %(name)s            Name of the logger (logging channel)    %(levelno)s         Numeric logging level for the message (DEBUG, INFO,                        WARNING, ERROR, CRITICAL)    %(levelname)s       Text logging level for the message ("DEBUG", "INFO",                        "WARNING", "ERROR", "CRITICAL")    %(pathname)s        Full pathname of the source file where the logging                        call was issued (if available)    %(filename)s        Filename portion of pathname    %(module)s          Module (name portion of filename)    %(lineno)d          Source line number where the logging call was issued                        (if available)    %(funcName)s        Function name    %(created)f         Time when the LogRecord was created (time.time()                        return value)    %(asctime)s         Textual time when the LogRecord was created    %(msecs)d           Millisecond portion of the creation time    %(relativeCreated)d Time in milliseconds when the LogRecord was created,                        relative to the time the logging module was loaded                        (typically at application startup time)    %(thread)d          Thread ID (if available)    %(threadName)s      Thread name (if available)    %(process)d         Process ID (if available)    %(message)s         The result of record.getMessage(), computed just as                        the record is emitted    """     converter = time.localtime     def __init__(self, fmt=None, datefmt=None):        """        Initialize the formatter with specified format strings.         Initialize the formatter either with the specified format string, or a        default as described above. Allow for specialized date formatting with        the optional datefmt argument (if omitted, you get the ISO8601 format).        """        if fmt:            self._fmt = fmt        else:            self._fmt = "%(message)s"        self.datefmt = datefmt     def formatTime(self, record, datefmt=None):        """        Return the creation time of the specified LogRecord as formatted text.         This method should be called from format() by a formatter which        wants to make use of a formatted time. This method can be overridden        in formatters to provide for any specific requirement, but the        basic behaviour is as follows: if datefmt (a string) is specified,        it is used with time.strftime() to format the creation time of the        record. Otherwise, the ISO8601 format is used. The resulting        string is returned. This function uses a user-configurable function        to convert the creation time to a tuple. By default, time.localtime()        is used; to change this for a particular formatter instance, set the        'converter' attribute to a function with the same signature as        time.localtime() or time.gmtime(). To change it for all formatters,        for example if you want all logging times to be shown in GMT,        set the 'converter' attribute in the Formatter class.        """        ct = self.converter(record.created)        if datefmt:            s = time.strftime(datefmt, ct)        else:            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)            s = "%s,%03d" % (t, record.msecs)        return s     def formatException(self, ei):        """        Format and return the specified exception information as a string.         This default implementation just uses        traceback.print_exception()        """        sio = cStringIO.StringIO()        traceback.print_exception(ei[0], ei[1], ei[2], None, sio)        s = sio.getvalue()        sio.close()        if s[-1] == "\n":            s = s[:-1]        return s     def format(self, record):        """        Format the specified record as text.         The record's attribute dictionary is used as the operand to a        string formatting operation which yields the returned string.        Before formatting the dictionary, a couple of preparatory steps        are carried out. The message attribute of the record is computed        using LogRecord.getMessage(). If the formatting string contains        "%(asctime)", formatTime() is called to format the event time.        If there is exception information, it is formatted using        formatException() and appended to the message.        """        record.message = record.getMessage()        if string.find(self._fmt,"%(asctime)") >= 0:            record.asctime = self.formatTime(record, self.datefmt)        s = self._fmt % record.__dict__        if record.exc_info:            # Cache the traceback text to avoid converting it multiple times            # (it's constant anyway)            if not record.exc_text:                record.exc_text = self.formatException(record.exc_info)        if record.exc_text:            if s[-1] != "\n":                s = s + "\n"            s = s + record.exc_text        return s ##   The default formatter to use when no other is specified#_defaultFormatter = Formatter() class BufferingFormatter:    """    A formatter suitable for formatting a number of records.    """    def __init__(self, linefmt=None):        """        Optionally specify a formatter which will be used to format each        individual record.        """        if linefmt:            self.linefmt = linefmt        else:            self.linefmt = _defaultFormatter     def formatHeader(self, records):        """        Return the header string for the specified records.        """        return ""     def formatFooter(self, records):        """        Return the footer string for the specified records.        """        return ""     def format(self, records):        """        Format the specified records and return the result as a string.        """        rv = ""        if len(records) > 0:            rv = rv + self.formatHeader(records)            for record in records:                rv = rv + self.linefmt.format(record)            rv = rv + self.formatFooter(records)        return rv #---------------------------------------------------------------------------#   Filter classes and functions#--------------------------------------------------------------------------- class Filter:    """    Filter instances are used to perform arbitrary filtering of LogRecords.     Loggers and Handlers can optionally use Filter instances to filter    records as desired. The base filter class only allows events which are    below a certain point in the logger hierarchy. For example, a filter    initialized with "A.B" will allow events logged by loggers "A.B",    "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If    initialized with the empty string, all events are passed.    """    def __init__(self, name=''):        """        Initialize a filter.         Initialize with the name of the logger which, together with its        children, will have its events allowed through the filter. If no        name is specified, allow every event.        """        self.name = name        self.nlen = len(name)

Lines 1–500 of 1372.