summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Defaults.py.in18
-rw-r--r--Mailman/loginit.py108
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)