diff options
| author | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2008-02-27 01:26:18 -0500 |
| commit | a1c73f6c305c7f74987d99855ba59d8fa823c253 (patch) | |
| tree | 65696889450862357c9e05c8e9a589f1bdc074ac /mailman/loginit.py | |
| parent | 3f31f8cce369529d177cfb5a7c66346ec1e12130 (diff) | |
| download | mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.gz mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.tar.zst mailman-a1c73f6c305c7f74987d99855ba59d8fa823c253.zip | |
Bite the bullet: rename the Mailman package to mailman.
Diffstat (limited to 'mailman/loginit.py')
| -rw-r--r-- | mailman/loginit.py | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/mailman/loginit.py b/mailman/loginit.py new file mode 100644 index 000000000..2fc6d88ef --- /dev/null +++ b/mailman/loginit.py @@ -0,0 +1,157 @@ +# Copyright (C) 2006-2008 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +"""Logging initialization, using Python's standard logging package. + +This module cannot be called 'logging' because that would interfere with the +import below. Ah, for Python 2.5 and absolute imports. +""" + +import os +import sys +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', # 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 + self._stream = self._open() + logging.Handler.__init__(self) + + def _open(self): + return codecs.open(self._filename, 'a', 'utf-8') + + def flush(self): + if self._stream: + self._stream.flush() + + def emit(self, record): + # It's possible for the stream to have been closed by the time we get + # here, due to the shut down semantics. This mostly happens in the + # test suite, but be defensive anyway. + stream = self._stream or sys.stderr + try: + msg = self.format(record) + fs = '%s\n' + try: + stream.write(fs % msg) + except UnicodeError: + stream.write(fs % msg.encode('string-escape')) + self.flush() + except: + self.handleError(record) + + def close(self): + self.flush() + self._stream.close() + self._stream = None + logging.Handler.close(self) + + def reopen(self): + self._stream.close() + self._stream = self._open() + + + +def initialize(propagate=False): + # 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: + path = os.path.join(config.ETC_DIR, config.LOG_CONFIG_FILE) + cp.read(os.path.normpath(path)) + # 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 = 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) + + + +def reopen(): + for handler in _handlers: + handler.reopen() |
