Back to index

moin  1.9.0~rc2
log.py
Go to the documentation of this file.
00001 # -*- coding: iso-8859-1 -*-
00002 """
00003     MoinMoin - init "logging" system
00004 
00005     WARNING
00006     -------
00007     logging must be configured VERY early, before the code in log.getLogger
00008     gets executed. Thus, logging is configured either by:
00009     a) an environment variable MOINLOGGINGCONF that contains the path/filename
00010        of a logging configuration file - this method overrides all following
00011        methods (except if it can't read or use that configuration, then it
00012        will use c))
00013     b) by an explicit call to MoinMoin.log.load_config('logging.conf') -
00014        you need to do this very early or a) or c) will happen before
00015     c) by using a builtin fallback logging conf
00016 
00017     If logging is not yet configured, log.getLogger will do an implicit
00018     configuration call - then a) or c) is done.
00019 
00020     Usage (for wiki server admins)
00021     ------------------------------
00022     Either use something like this in some shell script:
00023     MOINLOGGINGCONF=/path/to/logging.conf
00024     export MOINLOGGINGCONF
00025 
00026     Or, modify your server adaptor script (e.g. moin.cgi) to do this:
00027 
00028     from MoinMoin import log
00029     log.load_config('wiki/config/logging/logfile') # XXX please fix this path!
00030 
00031     You have to fix that path to use a logging configuration matching your
00032     needs (we provide some examples in the path given there, it is relative to
00033     the uncompressed moin distribution archive - if you use some moin package,
00034     you maybe find it under /usr/share/moin/).
00035     It is likely that you also have to edit the sample logging configurations
00036     we provide (e.g. to fix the logfile location).
00037 
00038     Usage (for developers)
00039     ----------------------
00040     If you write code for moin, do this at top of your module:
00041 
00042     from MoinMoin import log
00043     logging = log.getLogger(__name__)
00044 
00045     This will create a logger with 'MoinMoin.your.module' as name.
00046     The logger can optionally get configured in the logging configuration.
00047     If you don't configure it, some upperlevel logger (e.g. the root logger)
00048     will do the logging.
00049 
00050     @copyright: 2008 MoinMoin:ThomasWaldmann,
00051                 2007 MoinMoin:JohannesBerg
00052     @license: GNU GPL, see COPYING for details.
00053 """
00054 
00055 # This is the "last resort" fallback logging configuration for the case
00056 # that load_config() is either not called at all or with a non-working
00057 # logging configuration.
00058 # See http://www.python.org/doc/lib/logging-config-fileformat.html
00059 # We just use stderr output by default, if you want anything else,
00060 # you will have to configure logging.
00061 logging_defaults = {
00062     'loglevel': 'INFO',
00063 }
00064 logging_config = """\
00065 [loggers]
00066 keys=root
00067 
00068 [handlers]
00069 keys=stderr
00070 
00071 [formatters]
00072 keys=default
00073 
00074 [logger_root]
00075 level=%(loglevel)s
00076 handlers=stderr
00077 
00078 [handler_stderr]
00079 class=StreamHandler
00080 level=NOTSET
00081 formatter=default
00082 args=(sys.stderr, )
00083 
00084 [formatter_default]
00085 format=%(asctime)s %(levelname)s %(name)s:%(lineno)d %(message)s
00086 datefmt=
00087 class=logging.Formatter
00088 """
00089 
00090 import os
00091 import logging
00092 import logging.config
00093 import logging.handlers  # needed for handlers defined there being configurable in logging.conf file
00094 
00095 configured = False
00096 fallback_config = False
00097 
00098 import warnings
00099 
00100 # 'CacheNeedsUpdate' string exception in Page.py is supported for backwards compat reasons:
00101 warnings.filterwarnings('ignore', r'catching of string exceptions is deprecated', module='MoinMoin.Page')
00102 
00103 # TODO: subprocess was added in python 2.4, we now can refactor the code to use it and remove this:
00104 warnings.filterwarnings('ignore', r'The popen\d? module is deprecated.  Use the subprocess module.')
00105 
00106 
00107 def _log_warning(message, category, filename, lineno, file=None, line=None):
00108     # for warnings, we just want to use the logging system, not stderr or other files
00109     msg = "%s:%s: %s: %s" % (filename, lineno, category.__name__, message)
00110     logger = getLogger(__name__)
00111     logger.warning(msg) # Note: the warning will look like coming from here,
00112                         # but msg contains info about where it really comes from
00113 
00114 
00115 def load_config(conf_fname=None):
00116     """ load logging config from conffile """
00117     global configured
00118     err_msg = None
00119     conf_fname = os.environ.get('MOINLOGGINGCONF', conf_fname)
00120     if conf_fname:
00121         try:
00122             conf_fname = os.path.abspath(conf_fname)
00123             logging.config.fileConfig(conf_fname)
00124             configured = True
00125             l = getLogger(__name__)
00126             l.info('using logging configuration read from "%s"' % conf_fname)
00127             warnings.showwarning = _log_warning
00128         except Exception, err: # XXX be more precise
00129             err_msg = str(err)
00130     if not configured:
00131         # load builtin fallback logging config
00132         from StringIO import StringIO
00133         config_file = StringIO(logging_config)
00134         logging.config.fileConfig(config_file, logging_defaults)
00135         configured = True
00136         l = getLogger(__name__)
00137         if err_msg:
00138             l.warning('load_config for "%s" failed with "%s".' % (conf_fname, err_msg))
00139         l.warning('using logging configuration read from built-in fallback in MoinMoin.log module!')
00140         warnings.showwarning = _log_warning
00141 
00142 
00143 def getLogger(name):
00144     """ wrapper around logging.getLogger, so we can do some more stuff:
00145         - preprocess logger name
00146         - patch loglevel constants into logger object, so it can be used
00147           instead of the logging module
00148     """
00149     if not configured:
00150         load_config()
00151     logger = logging.getLogger(name)
00152     for levelnumber, levelname in logging._levelNames.items():
00153         if isinstance(levelnumber, int): # that list has also the reverse mapping...
00154             setattr(logger, levelname, levelnumber)
00155     return logger
00156