python-2.5.2/win32/Lib/logging/config.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 # Copyright 2001-2005 by Vinay Sajip. All Rights Reserved.
       
     2 #
       
     3 # Permission to use, copy, modify, and distribute this software and its
       
     4 # documentation for any purpose and without fee is hereby granted,
       
     5 # provided that the above copyright notice appear in all copies and that
       
     6 # both that copyright notice and this permission notice appear in
       
     7 # supporting documentation, and that the name of Vinay Sajip
       
     8 # not be used in advertising or publicity pertaining to distribution
       
     9 # of the software without specific, written prior permission.
       
    10 # VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
       
    11 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
       
    12 # VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
       
    13 # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
       
    14 # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
       
    15 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       
    16 
       
    17 """
       
    18 Configuration functions for the logging package for Python. The core package
       
    19 is based on PEP 282 and comments thereto in comp.lang.python, and influenced
       
    20 by Apache's log4j system.
       
    21 
       
    22 Should work under Python versions >= 1.5.2, except that source line
       
    23 information is not available unless 'sys._getframe()' is.
       
    24 
       
    25 Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
       
    26 
       
    27 To use, simply 'import logging' and log away!
       
    28 """
       
    29 
       
    30 import sys, logging, logging.handlers, string, socket, struct, os, traceback, types
       
    31 
       
    32 try:
       
    33     import thread
       
    34     import threading
       
    35 except ImportError:
       
    36     thread = None
       
    37 
       
    38 from SocketServer import ThreadingTCPServer, StreamRequestHandler
       
    39 
       
    40 
       
    41 DEFAULT_LOGGING_CONFIG_PORT = 9030
       
    42 
       
    43 if sys.platform == "win32":
       
    44     RESET_ERROR = 10054   #WSAECONNRESET
       
    45 else:
       
    46     RESET_ERROR = 104     #ECONNRESET
       
    47 
       
    48 #
       
    49 #   The following code implements a socket listener for on-the-fly
       
    50 #   reconfiguration of logging.
       
    51 #
       
    52 #   _listener holds the server object doing the listening
       
    53 _listener = None
       
    54 
       
    55 def fileConfig(fname, defaults=None):
       
    56     """
       
    57     Read the logging configuration from a ConfigParser-format file.
       
    58 
       
    59     This can be called several times from an application, allowing an end user
       
    60     the ability to select from various pre-canned configurations (if the
       
    61     developer provides a mechanism to present the choices and load the chosen
       
    62     configuration).
       
    63     In versions of ConfigParser which have the readfp method [typically
       
    64     shipped in 2.x versions of Python], you can pass in a file-like object
       
    65     rather than a filename, in which case the file-like object will be read
       
    66     using readfp.
       
    67     """
       
    68     import ConfigParser
       
    69 
       
    70     cp = ConfigParser.ConfigParser(defaults)
       
    71     if hasattr(cp, 'readfp') and hasattr(fname, 'readline'):
       
    72         cp.readfp(fname)
       
    73     else:
       
    74         cp.read(fname)
       
    75 
       
    76     formatters = _create_formatters(cp)
       
    77 
       
    78     # critical section
       
    79     logging._acquireLock()
       
    80     try:
       
    81         logging._handlers.clear()
       
    82         del logging._handlerList[:]
       
    83         # Handlers add themselves to logging._handlers
       
    84         handlers = _install_handlers(cp, formatters)
       
    85         _install_loggers(cp, handlers)
       
    86     finally:
       
    87         logging._releaseLock()
       
    88 
       
    89 
       
    90 def _resolve(name):
       
    91     """Resolve a dotted name to a global object."""
       
    92     name = string.split(name, '.')
       
    93     used = name.pop(0)
       
    94     found = __import__(used)
       
    95     for n in name:
       
    96         used = used + '.' + n
       
    97         try:
       
    98             found = getattr(found, n)
       
    99         except AttributeError:
       
   100             __import__(used)
       
   101             found = getattr(found, n)
       
   102     return found
       
   103 
       
   104 
       
   105 def _create_formatters(cp):
       
   106     """Create and return formatters"""
       
   107     flist = cp.get("formatters", "keys")
       
   108     if not len(flist):
       
   109         return {}
       
   110     flist = string.split(flist, ",")
       
   111     formatters = {}
       
   112     for form in flist:
       
   113         sectname = "formatter_%s" % string.strip(form)
       
   114         opts = cp.options(sectname)
       
   115         if "format" in opts:
       
   116             fs = cp.get(sectname, "format", 1)
       
   117         else:
       
   118             fs = None
       
   119         if "datefmt" in opts:
       
   120             dfs = cp.get(sectname, "datefmt", 1)
       
   121         else:
       
   122             dfs = None
       
   123         c = logging.Formatter
       
   124         if "class" in opts:
       
   125             class_name = cp.get(sectname, "class")
       
   126             if class_name:
       
   127                 c = _resolve(class_name)
       
   128         f = c(fs, dfs)
       
   129         formatters[form] = f
       
   130     return formatters
       
   131 
       
   132 
       
   133 def _install_handlers(cp, formatters):
       
   134     """Install and return handlers"""
       
   135     hlist = cp.get("handlers", "keys")
       
   136     if not len(hlist):
       
   137         return {}
       
   138     hlist = string.split(hlist, ",")
       
   139     handlers = {}
       
   140     fixups = [] #for inter-handler references
       
   141     for hand in hlist:
       
   142         sectname = "handler_%s" % string.strip(hand)
       
   143         klass = cp.get(sectname, "class")
       
   144         opts = cp.options(sectname)
       
   145         if "formatter" in opts:
       
   146             fmt = cp.get(sectname, "formatter")
       
   147         else:
       
   148             fmt = ""
       
   149         klass = eval(klass, vars(logging))
       
   150         args = cp.get(sectname, "args")
       
   151         args = eval(args, vars(logging))
       
   152         h = apply(klass, args)
       
   153         if "level" in opts:
       
   154             level = cp.get(sectname, "level")
       
   155             h.setLevel(logging._levelNames[level])
       
   156         if len(fmt):
       
   157             h.setFormatter(formatters[fmt])
       
   158         #temporary hack for FileHandler and MemoryHandler.
       
   159         if klass == logging.handlers.MemoryHandler:
       
   160             if "target" in opts:
       
   161                 target = cp.get(sectname,"target")
       
   162             else:
       
   163                 target = ""
       
   164             if len(target): #the target handler may not be loaded yet, so keep for later...
       
   165                 fixups.append((h, target))
       
   166         handlers[hand] = h
       
   167     #now all handlers are loaded, fixup inter-handler references...
       
   168     for h, t in fixups:
       
   169         h.setTarget(handlers[t])
       
   170     return handlers
       
   171 
       
   172 
       
   173 def _install_loggers(cp, handlers):
       
   174     """Create and install loggers"""
       
   175 
       
   176     # configure the root first
       
   177     llist = cp.get("loggers", "keys")
       
   178     llist = string.split(llist, ",")
       
   179     llist = map(lambda x: string.strip(x), llist)
       
   180     llist.remove("root")
       
   181     sectname = "logger_root"
       
   182     root = logging.root
       
   183     log = root
       
   184     opts = cp.options(sectname)
       
   185     if "level" in opts:
       
   186         level = cp.get(sectname, "level")
       
   187         log.setLevel(logging._levelNames[level])
       
   188     for h in root.handlers[:]:
       
   189         root.removeHandler(h)
       
   190     hlist = cp.get(sectname, "handlers")
       
   191     if len(hlist):
       
   192         hlist = string.split(hlist, ",")
       
   193         for hand in hlist:
       
   194             log.addHandler(handlers[string.strip(hand)])
       
   195 
       
   196     #and now the others...
       
   197     #we don't want to lose the existing loggers,
       
   198     #since other threads may have pointers to them.
       
   199     #existing is set to contain all existing loggers,
       
   200     #and as we go through the new configuration we
       
   201     #remove any which are configured. At the end,
       
   202     #what's left in existing is the set of loggers
       
   203     #which were in the previous configuration but
       
   204     #which are not in the new configuration.
       
   205     existing = root.manager.loggerDict.keys()
       
   206     #now set up the new ones...
       
   207     for log in llist:
       
   208         sectname = "logger_%s" % log
       
   209         qn = cp.get(sectname, "qualname")
       
   210         opts = cp.options(sectname)
       
   211         if "propagate" in opts:
       
   212             propagate = cp.getint(sectname, "propagate")
       
   213         else:
       
   214             propagate = 1
       
   215         logger = logging.getLogger(qn)
       
   216         if qn in existing:
       
   217             existing.remove(qn)
       
   218         if "level" in opts:
       
   219             level = cp.get(sectname, "level")
       
   220             logger.setLevel(logging._levelNames[level])
       
   221         for h in logger.handlers[:]:
       
   222             logger.removeHandler(h)
       
   223         logger.propagate = propagate
       
   224         logger.disabled = 0
       
   225         hlist = cp.get(sectname, "handlers")
       
   226         if len(hlist):
       
   227             hlist = string.split(hlist, ",")
       
   228             for hand in hlist:
       
   229                 logger.addHandler(handlers[string.strip(hand)])
       
   230 
       
   231     #Disable any old loggers. There's no point deleting
       
   232     #them as other threads may continue to hold references
       
   233     #and by disabling them, you stop them doing any logging.
       
   234     for log in existing:
       
   235         root.manager.loggerDict[log].disabled = 1
       
   236 
       
   237 
       
   238 def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
       
   239     """
       
   240     Start up a socket server on the specified port, and listen for new
       
   241     configurations.
       
   242 
       
   243     These will be sent as a file suitable for processing by fileConfig().
       
   244     Returns a Thread object on which you can call start() to start the server,
       
   245     and which you can join() when appropriate. To stop the server, call
       
   246     stopListening().
       
   247     """
       
   248     if not thread:
       
   249         raise NotImplementedError, "listen() needs threading to work"
       
   250 
       
   251     class ConfigStreamHandler(StreamRequestHandler):
       
   252         """
       
   253         Handler for a logging configuration request.
       
   254 
       
   255         It expects a completely new logging configuration and uses fileConfig
       
   256         to install it.
       
   257         """
       
   258         def handle(self):
       
   259             """
       
   260             Handle a request.
       
   261 
       
   262             Each request is expected to be a 4-byte length, packed using
       
   263             struct.pack(">L", n), followed by the config file.
       
   264             Uses fileConfig() to do the grunt work.
       
   265             """
       
   266             import tempfile
       
   267             try:
       
   268                 conn = self.connection
       
   269                 chunk = conn.recv(4)
       
   270                 if len(chunk) == 4:
       
   271                     slen = struct.unpack(">L", chunk)[0]
       
   272                     chunk = self.connection.recv(slen)
       
   273                     while len(chunk) < slen:
       
   274                         chunk = chunk + conn.recv(slen - len(chunk))
       
   275                     #Apply new configuration. We'd like to be able to
       
   276                     #create a StringIO and pass that in, but unfortunately
       
   277                     #1.5.2 ConfigParser does not support reading file
       
   278                     #objects, only actual files. So we create a temporary
       
   279                     #file and remove it later.
       
   280                     file = tempfile.mktemp(".ini")
       
   281                     f = open(file, "w")
       
   282                     f.write(chunk)
       
   283                     f.close()
       
   284                     try:
       
   285                         fileConfig(file)
       
   286                     except (KeyboardInterrupt, SystemExit):
       
   287                         raise
       
   288                     except:
       
   289                         traceback.print_exc()
       
   290                     os.remove(file)
       
   291             except socket.error, e:
       
   292                 if type(e.args) != types.TupleType:
       
   293                     raise
       
   294                 else:
       
   295                     errcode = e.args[0]
       
   296                     if errcode != RESET_ERROR:
       
   297                         raise
       
   298 
       
   299     class ConfigSocketReceiver(ThreadingTCPServer):
       
   300         """
       
   301         A simple TCP socket-based logging config receiver.
       
   302         """
       
   303 
       
   304         allow_reuse_address = 1
       
   305 
       
   306         def __init__(self, host='localhost', port=DEFAULT_LOGGING_CONFIG_PORT,
       
   307                      handler=None):
       
   308             ThreadingTCPServer.__init__(self, (host, port), handler)
       
   309             logging._acquireLock()
       
   310             self.abort = 0
       
   311             logging._releaseLock()
       
   312             self.timeout = 1
       
   313 
       
   314         def serve_until_stopped(self):
       
   315             import select
       
   316             abort = 0
       
   317             while not abort:
       
   318                 rd, wr, ex = select.select([self.socket.fileno()],
       
   319                                            [], [],
       
   320                                            self.timeout)
       
   321                 if rd:
       
   322                     self.handle_request()
       
   323                 logging._acquireLock()
       
   324                 abort = self.abort
       
   325                 logging._releaseLock()
       
   326 
       
   327     def serve(rcvr, hdlr, port):
       
   328         server = rcvr(port=port, handler=hdlr)
       
   329         global _listener
       
   330         logging._acquireLock()
       
   331         _listener = server
       
   332         logging._releaseLock()
       
   333         server.serve_until_stopped()
       
   334 
       
   335     return threading.Thread(target=serve,
       
   336                             args=(ConfigSocketReceiver,
       
   337                                   ConfigStreamHandler, port))
       
   338 
       
   339 def stopListening():
       
   340     """
       
   341     Stop the listening server which was created with a call to listen().
       
   342     """
       
   343     global _listener
       
   344     if _listener:
       
   345         logging._acquireLock()
       
   346         _listener.abort = 1
       
   347         _listener = None
       
   348         logging._releaseLock()