summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/loginit.py29
-rw-r--r--bin/mailmanctl65
-rw-r--r--bin/qrunner3
-rw-r--r--cron/disabled32
-rwxr-xr-xcron/gate_news77
5 files changed, 104 insertions, 102 deletions
diff --git a/Mailman/loginit.py b/Mailman/loginit.py
index 323bd2985..a0a0699e3 100644
--- a/Mailman/loginit.py
+++ b/Mailman/loginit.py
@@ -21,8 +21,8 @@ import below. Ah, for Python 2.5 and absolute imports.
"""
import os
+import codecs
import logging
-import logging.handlers
from Mailman import mm_cfg
@@ -37,6 +37,25 @@ _handlers = []
+class ReopenableFileHandler(logging.FileHandler):
+ def __init__(self, filename, mode='a', encoding=None):
+ # Unfortunately, FileHandler's __init__() doesn't store encoding.
+ logging.FileHandler.__init__(self, filename, mode, encoding)
+ self.encoding = encoding
+
+ def reopen(self):
+ # Flush and close the file/stream, then reopen it. WIBNI the base
+ # FileHandler supported this?
+ self.flush()
+ self.stream.close()
+ if self.encoding is None:
+ stream = open(self.baseFilename, self.mode)
+ else:
+ stream = codecs.open(self.baseFilename, mode, self.encoding)
+ self.stream = stream
+
+
+
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
@@ -72,9 +91,7 @@ def initialize(propagate=False):
# 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 = logging.handlers.RotatingFileHandler(
- os.path.join(mm_cfg.LOG_DIR, logger),
- maxBytes=0, backupCount=0)
+ handler = ReopenableFileHandler(os.path.join(mm_cfg.LOG_DIR, logger))
_handlers.append(handler)
handler.setFormatter(formatter)
log.addHandler(handler)
@@ -83,6 +100,4 @@ def initialize(propagate=False):
def reopen():
for handler in _handlers:
- meth = getattr(handler, 'doRollover', None)
- if meth:
- meth()
+ handler.reopen()
diff --git a/bin/mailmanctl b/bin/mailmanctl
index 473c94708..36c3ab545 100644
--- a/bin/mailmanctl
+++ b/bin/mailmanctl
@@ -92,25 +92,24 @@ Commands:
next time a message is written to them
"""
-import sys
import os
-import time
+import grp
+import pwd
+import sys
+import errno
import getopt
import signal
-import errno
-import pwd
-import grp
import socket
+import logging
import paths
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import LockFile
from Mailman import Errors
+from Mailman import LockFile
+from Mailman import Utils
+from Mailman import loginit
+from Mailman import mm_cfg
from Mailman.MailList import MailList
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
-from Mailman.Logging.Utils import LogStdErr
PROGRAM = sys.argv[0]
COMMASPACE = ', '
@@ -124,7 +123,9 @@ LOCK_LIFETIME = mm_cfg.days(1) + mm_cfg.hours(6)
SNOOZE = mm_cfg.days(1)
MAX_RESTARTS = 10
-LogStdErr('error', 'mailmanctl', manual_reprime=0)
+loginit.initialize()
+elog = logging.getLogger('mailman.error')
+qlog = logging.getLogger('mailman.qrunner')
@@ -167,8 +168,10 @@ def kill_watcher(sig):
def get_lock_data():
# Return the hostname, pid, and tempfile
fp = open(LOCKFILE)
- filename = os.path.split(fp.read().strip())[1]
- fp.close()
+ try:
+ filename = os.path.split(fp.read().strip())[1]
+ finally:
+ fp.close()
parts = filename.split('.')
hostname = DOT.join(parts[1:-1])
pid = int(parts[-1])
@@ -186,7 +189,8 @@ def qrunner_state():
try:
os.kill(pid, 0)
except OSError, e:
- if e.errno <> errno.ESRCH: raise
+ if e.errno <> errno.ESRCH:
+ raise
return 0
return 1
@@ -274,10 +278,10 @@ def start_all_runners():
def check_for_site_list():
sitelistname = mm_cfg.MAILMAN_SITE_LIST
try:
- sitelist = MailList(sitelistname, lock=0)
+ sitelist = MailList(sitelistname, lock=False)
except Errors.MMUnknownListError:
print >> sys.stderr, _('Site list is missing: %(sitelistname)s')
- syslog('error', 'Site list is missing: %s', mm_cfg.MAILMAN_SITE_LIST)
+ elog.error('Site list is missing: %s', mm_cfg.MAILMAN_SITE_LIST)
sys.exit(1)
@@ -292,11 +296,7 @@ def check_privs():
# Set the process's supplimental groups.
groups = [x[2] for x in grp.getgrall() if mm_cfg.MAILMAN_USER in x[3]]
groups.append(gid)
- try:
- os.setgroups(groups)
- except AttributeError:
- # Python 2.1 doesn't have setgroups
- syslog('error', 'Warning: unable to setgroups(%s)' % groups)
+ os.setgroups(groups)
os.setgid(gid)
os.setuid(uid)
elif myuid <> uid:
@@ -439,14 +439,11 @@ def main():
# to all the qrunner children. This will tell them to close and
# reopen their log files
def sighup_handler(signum, frame, kids=kids):
- # Closing our syslog will cause it to be re-opened at the next log
- # print output.
- syslog.close()
+ loginit.reopen()
for pid in kids.keys():
os.kill(pid, signal.SIGHUP)
# And just to tweak things...
- syslog('qrunner',
- 'Master watcher caught SIGHUP. Re-opening log files.')
+ qlog.info('Master watcher caught SIGHUP. Re-opening log files.')
signal.signal(signal.SIGHUP, sighup_handler)
# We also need to install a SIGTERM handler because that's what init
# will kill this process with when changing run levels.
@@ -456,7 +453,7 @@ def main():
os.kill(pid, signal.SIGTERM)
except OSError, e:
if e.errno <> errno.ESRCH: raise
- syslog('qrunner', 'Master watcher caught SIGTERM. Exiting.')
+ qlog.info('Master watcher caught SIGTERM. Exiting.')
signal.signal(signal.SIGTERM, sigterm_handler)
# Finally, we need a SIGINT handler which will cause the sub-qrunners
# to exit, but the master will restart SIGINT'd sub-processes unless
@@ -464,12 +461,12 @@ def main():
def sigint_handler(signum, frame, kids=kids):
for pid in kids.keys():
os.kill(pid, signal.SIGINT)
- syslog('qrunner', 'Master watcher caught SIGINT. Restarting.')
+ qlog.info('Master watcher caught SIGINT. Restarting.')
signal.signal(signal.SIGINT, sigint_handler)
# Now we're ready to simply do our wait/restart loop. This is the
# master qrunner watcher.
try:
- while 1:
+ while True:
try:
pid, status = os.wait()
except OSError, e:
@@ -498,7 +495,7 @@ def main():
restarting = '[restarting]'
qrname, slice, count, restarts = kids[pid]
del kids[pid]
- syslog('qrunner', """\
+ qlog.info("""\
Master qrunner detected subprocess exit
(pid: %d, sig: %s, sts: %s, class: %s, slice: %d/%d) %s""",
pid, killsig, exitstatus, qrname,
@@ -507,7 +504,7 @@ Master qrunner detected subprocess exit
if exitstatus <> signal.SIGINT:
restarts += 1
if restarts > MAX_RESTARTS:
- syslog('qrunner', """\
+ qlog.info("""\
Qrunner %s reached maximum restart limit of %d, not restarting.""",
qrname, MAX_RESTARTS)
restarting = ''
@@ -526,10 +523,10 @@ Qrunner %s reached maximum restart limit of %d, not restarting.""",
except OSError, e:
if e.errno == errno.ESRCH:
# The child has already exited
- syslog('qrunner', 'ESRCH on pid: %d', pid)
+ qlog.info('ESRCH on pid: %d', pid)
del kids[pid]
# Wait for all the children to go away
- while 1:
+ while True:
try:
pid, status = os.wait()
except OSError, e:
@@ -539,7 +536,7 @@ Qrunner %s reached maximum restart limit of %d, not restarting.""",
raise
continue
# Finally, give up the lock
- lock.unlock(unconditionally=1)
+ lock.unlock(unconditionally=True)
os._exit(0)
diff --git a/bin/qrunner b/bin/qrunner
index c076b00cd..42248e472 100644
--- a/bin/qrunner
+++ b/bin/qrunner
@@ -81,7 +81,6 @@ import paths
from Mailman import mm_cfg
from Mailman import loginit
from Mailman.i18n import _
-from Mailman.Logging.Utils import LogStdErr
PROGRAM = sys.argv[0]
COMMASPACE = ', '
@@ -219,7 +218,7 @@ def main():
# stderr in addition to logging to the log files. We do this by passing a
# value of True to propagate, which allows the 'mailman' root logger to
# see the log messages.
- loginit.initialize(not AS_SUBPROC)
+ loginit.initialize(propagate=not AS_SUBPROC)
# Fast track for one infinite runner
if len(runners) == 1 and not once:
diff --git a/cron/disabled b/cron/disabled
index 6624ff21f..dfc88cdf5 100644
--- a/cron/disabled
+++ b/cron/disabled
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 2001-2004 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2006 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
@@ -14,7 +14,8 @@
#
# 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
"""Process disabled members, recommended once per day.
@@ -63,19 +64,21 @@ Options:
import sys
import time
import getopt
+import logging
import paths
# mm_cfg must be imported before the other modules, due to the side-effect of
# it hacking sys.paths to include site-packages. Without this, running this
# script from cron with python -S will fail.
from Mailman import mm_cfg
-from Mailman import Utils
+
+from Mailman import Errors
from Mailman import MailList
-from Mailman import Pending
from Mailman import MemberAdaptor
-from Mailman import Errors
+from Mailman import Pending
+from Mailman import Utils
+from Mailman import loginit
from Mailman.Bouncer import _BounceInfo
-from Mailman.Logging.Syslog import syslog
from Mailman.i18n import _
# Work around known problems with some RedHat cron daemons
@@ -84,6 +87,10 @@ signal.signal(signal.SIGCHLD, signal.SIG_DFL)
PROGRAM = sys.argv[0]
+loginit.initialize(properly=True)
+elog = logging.getLogger('mailman.error')
+blog = logging.getLogger('mailman.bounce')
+
def usage(code, msg=''):
@@ -181,8 +188,7 @@ def main():
# other reason.
status = mlist.getDeliveryStatus(member)
if status == MemberAdaptor.BYBOUNCE:
- syslog(
- 'error',
+ elog.error(
'%s disabled BYBOUNCE lacks bounce info, list: %s',
member, mlist.internal_name())
continue
@@ -198,17 +204,17 @@ def main():
notify.append(member)
# Now, send notifications to anyone who is due
for member in notify:
- syslog('bounce', 'Notifying disabled member %s for list: %s',
- member, mlist.internal_name())
+ blog.info('Notifying disabled member %s for list: %s',
+ member, mlist.internal_name())
try:
mlist.sendNextNotification(member)
except Errors.NotAMemberError:
# There must have been some problem with the data we have
# on this member. Most likely it's that they don't have a
# password assigned. Log this and delete the member.
- syslog('bounce',
- 'NotAMemberError when sending disabled notice: %s',
- member)
+ blog.info(
+ 'NotAMemberError when sending disabled notice: %s',
+ member)
mlist.ApprovedDeleteMember(member, 'cron/disabled')
mlist.Save()
finally:
diff --git a/cron/gate_news b/cron/gate_news
index a84731f3f..f0701ca8b 100755
--- a/cron/gate_news
+++ b/cron/gate_news
@@ -1,6 +1,6 @@
#! @PYTHON@
#
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
+# Copyright (C) 1998-2006 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
@@ -14,7 +14,8 @@
#
# 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
"""Poll the NNTP servers for messages to be gatewayed to mailing lists.
@@ -28,27 +29,31 @@ Where options are
"""
-import sys
import os
+import sys
import time
import getopt
import socket
+import logging
import nntplib
import paths
+# mm_cfg must be imported before the other modules, due to the side-effect of
+# it hacking sys.paths to include site-packages. Without this, running this
+# script from cron with python -S will fail.
+from Mailman import mm_cfg
+
# Import this /after/ paths so that the sys.path is properly hacked
import email.Errors
from email.Parser import Parser
-from Mailman import mm_cfg
+from Mailman import LockFile
from Mailman import MailList
-from Mailman import Utils
from Mailman import Message
-from Mailman import LockFile
-from Mailman.i18n import _
+from Mailman import Utils
+from Mailman import loginit
from Mailman.Queue.sbcache import get_switchboard
-from Mailman.Logging.Utils import LogStdErr
-from Mailman.Logging.Syslog import syslog
+from Mailman.i18n import _
# Work around known problems with some RedHat cron daemons
import signal
@@ -56,22 +61,11 @@ signal.signal(signal.SIGCHLD, signal.SIG_DFL)
GATENEWS_LOCK_FILE = os.path.join(mm_cfg.LOCK_DIR, 'gate_news.lock')
-LogStdErr('error', 'gate_news', manual_reprime=0)
-
LOCK_LIFETIME = mm_cfg.hours(2)
NL = '\n'
-# Continues inside try: block are not allowed in Python versions before 2.1.
-# This exception is used to work around that.
-class _ContinueLoop(Exception):
- pass
-
-
-try:
- True, False
-except NameError:
- True = 1
- False = 0
+loginit.initialize(propagate=True)
+log = logging.getLogger('mailman.fromusenet')
@@ -102,9 +96,8 @@ def open_newsgroup(mlist):
user=mm_cfg.NNTP_USERNAME,
password=mm_cfg.NNTP_PASSWORD)
except (socket.error, nntplib.NNTPError, IOError), e:
- syslog('fromusenet',
- 'error opening connection to nntp_host: %s\n%s',
- mlist.nntp_host, e)
+ log.error('error opening connection to nntp_host: %s\n%s',
+ mlist.nntp_host, e)
raise
_hostcache[mlist.nntp_host] = conn
# Get the GROUP information for the list, but we're only really interested
@@ -162,9 +155,8 @@ def poll_newsgroup(mlist, conn, first, last, glock):
try:
msg = p.parsestr(NL.join(lines))
except email.Errors.MessageError, e:
- syslog('fromusenet',
- 'email package exception for %s:%d\n%s',
- mlist.linked_newsgroup, num, e)
+ log.error('email package exception for %s:%d\n%s',
+ mlist.linked_newsgroup, num, e)
raise _ContinueLoop
if found_to:
del msg['X-Originally-To']
@@ -176,12 +168,9 @@ def poll_newsgroup(mlist, conn, first, last, glock):
inq.enqueue(msg,
listname = mlist.internal_name(),
fromusenet = 1)
- syslog('fromusenet',
- 'posted to list %s: %7d' % (listname, num))
+ log.info('posted to list %s: %7d', listname, num)
except nntplib.NNTPError, e:
- syslog('fromusenet',
- 'NNTP error for list %s: %7d' % (listname, num))
- syslog('fromusenet', str(e))
+ log.exception('NNTP error for list %s: %7d', listname, num)
except _ContinueLoop:
continue
# Even if we don't post the message because it was seen on the
@@ -208,7 +197,7 @@ def process_lists(glock):
conn, first, last = open_newsgroup(mlist)
except (socket.error, nntplib.NNTPError):
break
- syslog('fromusenet', '%s: [%d..%d]' % (listname, first, last))
+ log.info('%s: [%d..%d]', listname, first, last)
try:
try:
if watermark is None:
@@ -217,8 +206,7 @@ def process_lists(glock):
# newsgroup. We essentially do a mass catch-up, otherwise
# we'd flood the mailing list.
mlist.usenet_watermark = last
- syslog('fromusenet', '%s caught up to article %d' %
- (listname, last))
+ log.info('%s caught up to article %d', listname, last)
else:
# The list has been polled previously, so now we simply
# grab all the messages on the newsgroup that have not
@@ -229,25 +217,22 @@ def process_lists(glock):
# has run. Not much we can do about that.
start = max(watermark+1, first)
if start > last:
- syslog('fromusenet', 'nothing new for list %s' %
- listname)
+ log.info('nothing new for list %s', listname)
else:
mlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT)
- syslog('fromusenet', 'gating %s articles [%d..%d]' %
- (listname, start, last))
+ log.info('gating %s articles [%d..%d]',
+ listname, start, last)
# Use last+1 because poll_newsgroup() employes a for
# loop over range, and this will not include the last
# element in the list.
poll_newsgroup(mlist, conn, start, last+1, glock)
except LockFile.TimeOutError:
- syslog('fromusenet', 'Could not acquire list lock: %s' %
- listname)
+ log.error('Could not acquire list lock: %s', listname)
finally:
if mlist.Locked():
mlist.Save()
mlist.Unlock()
- syslog('fromusenet', '%s watermark: %d' %
- (listname, mlist.usenet_watermark))
+ log.info('%s watermark: %d', listname, mlist.usenet_watermark)
@@ -258,13 +243,13 @@ def main():
try:
lock.lock(timeout=0.5)
except LockFile.TimeOutError:
- syslog('fromusenet', 'Could not acquire gate_news lock')
+ log.error('Could not acquire gate_news lock')
return
try:
process_lists(lock)
finally:
clearcache()
- lock.unlock(unconditionally=1)
+ lock.unlock(unconditionally=True)