diff options
| -rw-r--r-- | Mailman/Defaults.py.in | 18 | ||||
| -rw-r--r-- | Mailman/loginit.py | 108 |
2 files changed, 79 insertions, 47 deletions
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in index 03c13bd86..7008be8f9 100644 --- a/Mailman/Defaults.py.in +++ b/Mailman/Defaults.py.in @@ -509,6 +509,24 @@ OWNER_PIPELINE = [ ] +# This defines a logging subsystem confirmation file, which overrides the +# default log settings. This is a ConfigParser formatted file which can +# contain sections named after the logger name (without the leading 'mailman.' +# common prefix). Each section may contain the following options: +# +# - level -- Overrides the default level; this may be any of the +# standard Python logging levels, case insensitive. +# - format -- Overrides the default format string; see below. +# - datefmt -- Overrides the default date format string; see below. +# - path -- Overrides the default logger path. This may be a relative +# path name, in which case it is relative to Mailman's LOG_DIR, +# or it may be an absolute path name. You cannot change the +# handler class that will be used. +# - propagate -- Boolean specifying whether to propagate log message from this +# logger to the root "mailman" logger. You cannot override +# settings for the root logger. +LOG_CONFIG_FILE = None + # This defines log format strings for the SMTPDirect delivery module (see # DELIVERY_MODULE above). Valid %()s string substitutions include: # diff --git a/Mailman/loginit.py b/Mailman/loginit.py index 70412f4da..71a5e9722 100644 --- a/Mailman/loginit.py +++ b/Mailman/loginit.py @@ -24,32 +24,52 @@ import below. Ah, for Python 2.5 and absolute imports. import os import codecs import logging +import ConfigParser from Mailman.configuration import config + + FMT = '%(asctime)s (%(process)d) %(message)s' DATEFMT = '%b %d %H:%M:%S %Y' + LOGGERS = ( - 'bounce', - 'config', - 'debug', - 'error', - 'fromusenet', - 'http', - 'locks', - 'mischief', - 'post', - 'qrunner', - 'smtp', - 'smtp-failure', - 'subscribe', - 'vette', + 'bounce', # All bounce processing logs go here + 'config', # Configuration issues + 'debug', # Only used for development + 'error', # All exceptions go to this log + 'fromusenet', # Information related to the Usenet to Mailman gateway + 'http', # Internal wsgi-based web interface + 'locks', # Lock state changes + 'mischief', # Various types of hostile activity + 'post', # Information about messages posted to mailing lists + 'qrunner', # qrunner start/stops + 'smtp', # Successful SMTP activity + 'smtp-failure', # Unsuccessful SMTP activity + 'subscribe', # Information about leaves/joins + 'vette', # Information related to admindb activity ) _handlers = [] +class ReallySafeConfigParser(ConfigParser.SafeConfigParser): + def getstring(self, section, option, default=None): + try: + return ConfigParser.SafeConfigParser.get(self, section, option) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return default + + def getboolean(self, section, option, default=None): + try: + return ConfigParser.SafeConfigParser.getboolean( + self, section, option) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return default + + + class ReopenableFileHandler(logging.Handler): def __init__(self, filename): self._filename = filename @@ -86,47 +106,41 @@ class ReopenableFileHandler(logging.Handler): def initialize(propagate=False): - # XXX Don't call logging.basicConfig() because in Python 2.3, it adds a - # handler to the root logger that we don't want. When Python 2.4 is the - # minimum requirement, we can use basicConfig() with keyword arguments. - # - # The current set of Mailman logs are: - # - # debug - Only used for development - # error - All exceptions go to this log - # bounce - All bounce processing logs go here - # mischief - Various types of hostile activity - # post - Information about messages posted to mailing lists - # vette - Information related to admindb activity - # smtp - Successful SMTP activity - # smtp-failure - Unsuccessful SMTP activity - # subscribe - Information about leaves/joins - # config - Configuration issues - # locks - Lock steals - # qrunner - qrunner start/stops - # fromusenet - Information related to the Usenet to Mailman gateway - # - # Start by creating a common formatter and the root logger. - formatter = logging.Formatter(fmt=FMT, datefmt=DATEFMT) - log = logging.getLogger('mailman') - handler = logging.StreamHandler() - handler.setFormatter(formatter) - log.addHandler(handler) - log.setLevel(logging.INFO) + # Initialize the root logger, then create a formatter for all the sublogs. + logging.basicConfig(format=FMT, datefmt=DATEFMT, level=logging.INFO) + # If a custom log configuration file was specified, load it now. Note + # that we don't use logging.config.fileConfig() because it requires that + # all loggers, formatters, and handlers be defined. We want to support + # minimal overloading of our logger configurations. + cp = ReallySafeConfigParser() + if config.LOG_CONFIG_FILE: + cp.read(config.LOG_CONFIG_FILE) # Create the subloggers for logger in LOGGERS: log = logging.getLogger('mailman.' + logger) + # Get settings from log configuration file (or defaults). + log_format = cp.getstring(logger, 'format', FMT) + log_datefmt = cp.getstring(logger, 'datefmt', DATEFMT) # Propagation to the root logger is how we handle logging to stderr # when the qrunners are not run as a subprocess of mailmanctl. - log.propagate = propagate - handler = ReopenableFileHandler(os.path.join(config.LOG_DIR, logger)) + log.propagate = cp.getboolean(logger, 'propagate', propagate) + # Set the logger's level. Note that if the log configuration file + # does not set an override, the default level will be INFO except for + # the 'debug' logger. It doesn't make much sense for the debug logger + # to ignore debug level messages! + level_str = cp.getstring(logger, 'level', 'INFO').upper() + level_def = (logging.DEBUG if logger == 'debug' else logging.INFO) + level_int = getattr(logging, level_str, level_def) + log.setLevel(level_int) + # Create a formatter for this logger, then a handler, and link the + # formatter to the handler. + formatter = logging.Formatter(fmt=log_format, datefmt=log_datefmt) + path_str = cp.getstring(logger, 'path', logger) + path_abs = os.path.normpath(os.path.join(config.LOG_DIR, path_str)) + handler = ReopenableFileHandler(path_abs) _handlers.append(handler) handler.setFormatter(formatter) log.addHandler(handler) - # It doesn't make much sense for the debug logger to ignore debug - # level messages. - if logger == 'debug': - log.setLevel(logging.DEBUG) |
