def fileConfig(fname, defaults=None, _vars=None): """ Read the logging configuration from a ConfigParser-format file. This can be called several times from an application, allowing an end user the ability to select from various pre-canned configurations (if the developer provides a mechanism to present the choices and load the chosen configuration). In versions of ConfigParser which have the readfp method [typically shipped in 2.x versions of Python], you can pass in a file-like object rather than a filename, in which case the file-like object will be read using readfp. Derived from python 2.4.4 but extended with _vars so that additional classes from other sides can be loaded. Just give _vars as dict with name->class. Also this method support xml config files (see XMLConfigParser) if fname ends with extension xml. """ #global _classregistry #print os.path.splitext(fname) from xml.dom import Node if isinstance(fname, Node) or os.path.splitext(fname)[1] == ".xml": from comoonics.tools.XMLConfigParser import ConfigParser else: from ConfigParser import ConfigParser logging.shutdown() cp = ConfigParser(defaults) if hasattr(cp, 'readfp') and hasattr(fname, 'readline'): cp.readfp(fname) else: cp.read(fname) #first, do the formatters... if cp.has_section("formatters"): flist = cp.get("formatters", "keys") if len(flist): flist = string.split(flist, ",") formatters = {} for form in flist: sectname = "formatter_%s" % form opts = cp.options(sectname) if "format" in opts: fs = cp.get(sectname, "format", 1) else: fs = None if "datefmt" in opts: dfs = cp.get(sectname, "datefmt", 1) else: dfs = None f = logging.Formatter(fs, dfs) formatters[form] = f #next, do the handlers... #critical section... logging._acquireLock() try: try: #first, lose the existing handlers... logging._handlers.clear() del logging._handlerList[:] #now set up the new ones... hlist = cp.get("handlers", "keys") _mylogger.debug("handlers: %s, %u" %(hlist, len(hlist))) if len(hlist): hlist = string.split(hlist, ",") handlers = {} fixups = [] #for inter-handler references for hand in hlist: try: hand=hand.strip() sectname = "handler_%s" % hand klass = cp.get(sectname, "class") opts = cp.options(sectname) if "formatter" in opts: fmt = cp.get(sectname, "formatter") else: fmt = "" if not _vars: _vars=vars(logging) else: _vars.update(vars(logging)) _vars.update(_classregistry) klass=eval(klass, _vars) args = cp.get(sectname, "args") #_mylogger.debug("comoonics.ComLog.fileConfig(_classregistry: %s)" %_classregistry) #_mylogger.debug("comoonics.ComLog.fileConfig(_vars: %s)" %_vars.keys()) args = eval(args, _vars) h = apply(klass, args) if "level" in opts: level = cp.get(sectname, "level") h.setLevel(logging._levelNames[level]) if len(fmt): h.setFormatter(formatters[fmt]) #temporary hack for FileHandler and MemoryHandler. if klass == logging.handlers.MemoryHandler: if "target" in opts: target = cp.get(sectname,"target") else: target = "" if len(target): #the target handler may not be loaded yet, so keep for later... fixups.append((h, target)) _mylogger.debug("handlers[%s]=%s" %(hand, h)) handlers[hand] = h except: #if an error occurs when instantiating a handler, too bad import warnings _mylogger.exception("Could not create handler: %s" %klass) #this could happen e.g. because of lack of privileges #now all handlers are loaded, fixup inter-handler references... for fixup in fixups: h = fixup[0] t = fixup[1] h.setTarget(handlers[t]) #at last, the loggers...first the root... llist = cp.get("loggers", "keys") llist = string.split(llist, ",") llist.remove("root") sectname = "logger_root" root = logging.root log = root opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") log.setLevel(logging._levelNames[level]) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") if len(hlist): hlist = string.split(hlist, ",") for hand in hlist: hand=hand.strip() log.addHandler(handlers[hand]) #and now the others... #we don't want to lose the existing loggers, #since other threads may have pointers to them. #existing is set to contain all existing loggers, #and as we go through the new configuration we #remove any which are configured. At the end, #what's left in existing is the set of loggers #which were in the previous configuration but #which are not in the new configuration. existing = root.manager.loggerDict.keys() #now set up the new ones... for log in llist: sectname = "logger_%s" % log qn = cp.get(sectname, "qualname") opts = cp.options(sectname) if "propagate" in opts: propagate = cp.getint(sectname, "propagate") else: propagate = 1 logger = logging.getLogger(qn) if qn in existing: existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") logger.setLevel(logging._levelNames[level]) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate logger.disabled = 0 hlist = cp.get(sectname, "handlers") if len(hlist): hlist = string.split(hlist, ",") for hand in hlist: hand=hand.strip() logger.addHandler(handlers[hand]) #Disable any old loggers. There's no point deleting #them as other threads may continue to hold references #and by disabling them, you stop them doing any logging. # MARC: I don't understand the following two lines why disabling the loggers if they might be used # or referenced again and are disabled then. #for log in existing: # root.manager.loggerDict[log].disabled = 1 except: ei = sys.exc_info() traceback.print_exception(ei[0], ei[1], ei[2], None, sys.stderr) del ei finally: logging._releaseLock()