aboutsummaryrefslogtreecommitdiffstats
path: root/Mailman/Logging
diff options
context:
space:
mode:
author <>2003-01-02 05:25:50 +0000
committer <>2003-01-02 05:25:50 +0000
commitb132a73f15e432eaf43310fce9196ca0c0651465 (patch)
treec15f816ba7c4de99fef510e3bd75af0890d47441 /Mailman/Logging
downloadmailman2-b132a73f15e432eaf43310fce9196ca0c0651465.tar.gz
mailman2-b132a73f15e432eaf43310fce9196ca0c0651465.tar.xz
mailman2-b132a73f15e432eaf43310fce9196ca0c0651465.zip
This commit was manufactured by cvs2svn to create branch
'Release_2_1-maint'.
Diffstat (limited to 'Mailman/Logging')
-rw-r--r--Mailman/Logging/.cvsignore1
-rw-r--r--Mailman/Logging/Logger.py103
-rw-r--r--Mailman/Logging/Makefile.in69
-rw-r--r--Mailman/Logging/MultiLogger.py76
-rw-r--r--Mailman/Logging/StampedLogger.py89
-rw-r--r--Mailman/Logging/Syslog.py69
-rw-r--r--Mailman/Logging/Utils.py52
-rw-r--r--Mailman/Logging/__init__.py15
8 files changed, 474 insertions, 0 deletions
diff --git a/Mailman/Logging/.cvsignore b/Mailman/Logging/.cvsignore
new file mode 100644
index 00000000..f3c7a7c5
--- /dev/null
+++ b/Mailman/Logging/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/Mailman/Logging/Logger.py b/Mailman/Logging/Logger.py
new file mode 100644
index 00000000..0cb7c6af
--- /dev/null
+++ b/Mailman/Logging/Logger.py
@@ -0,0 +1,103 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""File-based logger, writes to named category files in mm_cfg.LOG_DIR."""
+
+import sys
+import os
+import codecs
+from types import StringType
+
+from Mailman import mm_cfg
+from Mailman.Logging.Utils import _logexc
+
+# Set this to the encoding to be used for your log file output. If set to
+# None, then it uses your system's default encoding. Otherwise, it must be an
+# encoding string appropriate for codecs.open().
+LOG_ENCODING = 'iso-8859-1'
+
+
+
+class Logger:
+ def __init__(self, category, nofail=1, immediate=0):
+ """nofail says to fallback to sys.__stderr__ if write fails to
+ category file - a complaint message is emitted, but no exception is
+ raised. Set nofail=0 if you want to handle the error in your code,
+ instead.
+
+ immediate=1 says to create the log file on instantiation.
+ Otherwise, the file is created only when there are writes pending.
+ """
+ self.__filename = os.path.join(mm_cfg.LOG_DIR, category)
+ self.__fp = None
+ self.__nofail = nofail
+ self.__encoding = LOG_ENCODING or sys.getdefaultencoding()
+ if immediate:
+ self.__get_f()
+
+ def __del__(self):
+ self.close()
+
+ def __repr__(self):
+ return '<%s to %s>' % (self.__class__.__name__, `self.__filename`)
+
+ def __get_f(self):
+ if self.__fp:
+ return self.__fp
+ else:
+ try:
+ ou = os.umask(002)
+ try:
+ try:
+ f = codecs.open(
+ self.__filename, 'a+', self.__encoding, 'replace',
+ 1)
+ except LookupError:
+ f = open(self.__filename, 'a+', 1)
+ self.__fp = f
+ finally:
+ os.umask(ou)
+ except IOError, e:
+ if self.__nofail:
+ _logexc(self, e)
+ f = self.__fp = sys.__stderr__
+ else:
+ raise
+ return f
+
+ def flush(self):
+ f = self.__get_f()
+ if hasattr(f, 'flush'):
+ f.flush()
+
+ def write(self, msg):
+ if isinstance(msg, StringType):
+ msg = unicode(msg, self.__encoding)
+ f = self.__get_f()
+ try:
+ f.write(msg)
+ except IOError, msg:
+ _logexc(self, msg)
+
+ def writelines(self, lines):
+ for l in lines:
+ self.write(l)
+
+ def close(self):
+ if not self.__fp:
+ return
+ self.__get_f().close()
+ self.__fp = None
diff --git a/Mailman/Logging/Makefile.in b/Mailman/Logging/Makefile.in
new file mode 100644
index 00000000..407f39a9
--- /dev/null
+++ b/Mailman/Logging/Makefile.in
@@ -0,0 +1,69 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# NOTE: Makefile.in is converted into Makefile by the configure script
+# in the parent directory. Once configure has run, you can recreate
+# the Makefile by running just config.status.
+
+# Variables set by configure
+
+VPATH= @srcdir@
+srcdir= @srcdir@
+bindir= @bindir@
+prefix= @prefix@
+exec_prefix= @exec_prefix@
+
+CC= @CC@
+CHMOD= @CHMOD@
+INSTALL= @INSTALL@
+
+DEFS= @DEFS@
+
+# Customizable but not set by configure
+
+OPT= @OPT@
+CFLAGS= $(OPT) $(DEFS)
+PACKAGEDIR= $(prefix)/Mailman/Logging
+SHELL= /bin/sh
+
+MODULES= *.py
+
+# Modes for directories and executables created by the install
+# process. Default to group-writable directories but
+# user-only-writable for executables.
+DIRMODE= 775
+EXEMODE= 755
+FILEMODE= 644
+INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
+
+
+# Rules
+
+all:
+
+install:
+ for f in $(MODULES); \
+ do \
+ $(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(PACKAGEDIR); \
+ done
+
+finish:
+
+clean:
+
+distclean:
+ -rm *.pyc
+ -rm Makefile
diff --git a/Mailman/Logging/MultiLogger.py b/Mailman/Logging/MultiLogger.py
new file mode 100644
index 00000000..3ff11d27
--- /dev/null
+++ b/Mailman/Logging/MultiLogger.py
@@ -0,0 +1,76 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""A mutiple sink logger. Any message written goes to all sub-loggers."""
+
+import sys
+from Mailman.Logging.Utils import _logexc
+
+
+
+class MultiLogger:
+ def __init__(self, *args):
+ self.__loggers = []
+ for logger in args:
+ self.__loggers.append(logger)
+
+ def add_logger(self, logger):
+ if logger not in self.__loggers:
+ self.__loggers.append(logger)
+
+ def del_logger(self, logger):
+ if logger in self.__loggers:
+ self.__loggers.remove(logger)
+
+ def write(self, msg):
+ for logger in self.__loggers:
+ # you want to be sure that a bug in one logger doesn't prevent
+ # logging to all the other loggers
+ try:
+ logger.write(msg)
+ except:
+ _logexc(logger, msg)
+
+ def writelines(self, lines):
+ for line in lines:
+ self.write(line)
+
+ def flush(self):
+ for logger in self.__loggers:
+ if hasattr(logger, 'flush'):
+ # you want to be sure that a bug in one logger doesn't prevent
+ # logging to all the other loggers
+ try:
+ logger.flush()
+ except:
+ _logexc(logger)
+
+ def close(self):
+ for logger in self.__loggers:
+ # you want to be sure that a bug in one logger doesn't prevent
+ # logging to all the other loggers
+ try:
+ if logger <> sys.__stderr__ and logger <> sys.__stdout__:
+ logger.close()
+ except:
+ _logexc(logger)
+
+ def reprime(self):
+ for logger in self.__loggers:
+ try:
+ logger.reprime()
+ except AttributeError:
+ pass
diff --git a/Mailman/Logging/StampedLogger.py b/Mailman/Logging/StampedLogger.py
new file mode 100644
index 00000000..370f1af8
--- /dev/null
+++ b/Mailman/Logging/StampedLogger.py
@@ -0,0 +1,89 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import os
+import time
+
+from Mailman.Logging.Logger import Logger
+
+
+
+class StampedLogger(Logger):
+ """Record messages in log files, including date stamp and optional label.
+
+ If manual_reprime is on (off by default), then timestamp prefix will
+ included only on first .write() and on any write immediately following a
+ call to the .reprime() method. This is useful for when StampedLogger is
+ substituting for sys.stderr, where you'd like to see the grouping of
+ multiple writes under a single timestamp (and there is often is one group,
+ for uncaught exceptions where a script is bombing).
+
+ In any case, the identifying prefix will only follow writes that start on
+ a new line.
+
+ Nofail (by default) says to fallback to sys.stderr if write fails to
+ category file. A message is emitted, but the IOError is caught.
+ Initialize with nofail=0 if you want to handle the error in your code,
+ instead.
+
+ """
+ def __init__(self, category, label=None, manual_reprime=0, nofail=1,
+ immediate=1):
+ """If specified, optional label is included after timestamp.
+ Other options are passed to the Logger class initializer.
+ """
+ self.__label = label
+ self.__manual_reprime = manual_reprime
+ self.__primed = 1
+ self.__bol = 1
+ Logger.__init__(self, category, nofail, immediate)
+
+ def reprime(self):
+ """Reset so timestamp will be included with next write."""
+ self.__primed = 1
+
+ def write(self, msg):
+ if not self.__bol:
+ prefix = ""
+ else:
+ if not self.__manual_reprime or self.__primed:
+ stamp = time.strftime("%b %d %H:%M:%S %Y ",
+ time.localtime(time.time()))
+ self.__primed = 0
+ else:
+ stamp = ""
+ if self.__label is None:
+ label = "(%d)" % os.getpid()
+ else:
+ label = "%s(%d):" % (self.__label, os.getpid())
+ prefix = stamp + label
+ Logger.write(self, "%s %s" % (prefix, msg))
+ if msg and msg[-1] == '\n':
+ self.__bol = 1
+ else:
+ self.__bol = 0
+
+ def writelines(self, lines):
+ first = 1
+ for l in lines:
+ if first:
+ self.write(l)
+ first = 0
+ else:
+ if l and l[0] not in [' ', '\t', '\n']:
+ Logger.write(self, ' ' + l)
+ else:
+ Logger.write(self, l)
diff --git a/Mailman/Logging/Syslog.py b/Mailman/Logging/Syslog.py
new file mode 100644
index 00000000..3e8d557d
--- /dev/null
+++ b/Mailman/Logging/Syslog.py
@@ -0,0 +1,69 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Central logging class for the Mailman system.
+
+This might eventually be replaced by a syslog based logger, hence the name.
+"""
+
+from Mailman.Logging.StampedLogger import StampedLogger
+
+
+
+# Global, shared logger instance. All clients should use this object.
+syslog = None
+
+
+
+# Don't instantiate except below.
+class _Syslog:
+ def __init__(self):
+ self._logfiles = {}
+
+ def __del__(self):
+ self.close()
+
+ def write(self, kind, msg, *args, **kws):
+ self.write_ex(kind, msg, args, kws)
+
+ # We need this because SMTPDirect tries to pass in a special dict-like
+ # object, which is not a concrete dictionary. This is not allowed by
+ # Python's extended call syntax. :(
+ def write_ex(self, kind, msg, args=None, kws=None):
+ origmsg = msg
+ logf = self._logfiles.get(kind)
+ if not logf:
+ logf = self._logfiles[kind] = StampedLogger(kind)
+ try:
+ if args:
+ msg %= args
+ if kws:
+ msg %= kws
+ # It's really bad if exceptions in the syslogger cause other crashes
+ except Exception, e:
+ msg = 'Bad format "%s": %s: %s' % (origmsg, repr(e), e)
+ logf.write(msg + '\n')
+
+ # For the ultimate in convenience
+ __call__ = write
+
+ def close(self):
+ for kind, logger in self._logfiles.items():
+ logger.close()
+ self._logfiles.clear()
+
+
+syslog = _Syslog()
diff --git a/Mailman/Logging/Utils.py b/Mailman/Logging/Utils.py
new file mode 100644
index 00000000..ef119fb0
--- /dev/null
+++ b/Mailman/Logging/Utils.py
@@ -0,0 +1,52 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import sys
+import traceback
+
+
+def _logexc(logger=None, msg=''):
+ sys.__stderr__.write('Logging error: %s\n' % logger)
+ traceback.print_exc(file=sys.__stderr__)
+ sys.__stderr__.write('Original log message:\n%s\n' % msg)
+
+
+def LogStdErr(category, label, manual_reprime=1, tee_to_real_stderr=1):
+ """Establish a StampedLogger on sys.stderr if possible.
+
+ If tee_to_real_stderr is true, then the real standard error also gets
+ output, via a MultiLogger.
+
+ Returns the MultiLogger if successful, None otherwise.
+ """
+ from StampedLogger import StampedLogger
+ from MultiLogger import MultiLogger
+ try:
+ logger = StampedLogger(category,
+ label=label,
+ manual_reprime=manual_reprime,
+ nofail=0)
+ if tee_to_real_stderr:
+ if hasattr(sys, '__stderr__'):
+ stderr = sys.__stderr__
+ else:
+ stderr = sys.stderr
+ logger = MultiLogger(stderr, logger)
+ sys.stderr = logger
+ return sys.stderr
+ except IOError:
+ return None
+
diff --git a/Mailman/Logging/__init__.py b/Mailman/Logging/__init__.py
new file mode 100644
index 00000000..2cbbabb1
--- /dev/null
+++ b/Mailman/Logging/__init__.py
@@ -0,0 +1,15 @@
+# Copyright (C) 1998,1999,2000,2001,2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.