diff options
| -rw-r--r-- | Mailman/loginit.py | 29 | ||||
| -rw-r--r-- | bin/mailmanctl | 65 | ||||
| -rw-r--r-- | bin/qrunner | 3 | ||||
| -rw-r--r-- | cron/disabled | 32 | ||||
| -rwxr-xr-x | cron/gate_news | 77 |
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) |
