summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Archiver/Archiver.py10
-rw-r--r--Mailman/Archiver/HyperArch.py12
-rw-r--r--Mailman/Archiver/pipermail.py7
-rw-r--r--Mailman/BDBMemberAdaptor.py3
-rw-r--r--Mailman/Bouncer.py72
-rw-r--r--Mailman/Bouncers/BouncerAPI.py7
-rw-r--r--Mailman/Cgi/__init__.py15
-rw-r--r--Mailman/Cgi/admin.py7
-rw-r--r--Mailman/Cgi/admindb.py27
-rw-r--r--Mailman/Cgi/confirm.py5
-rw-r--r--Mailman/Cgi/create.py6
-rw-r--r--Mailman/Cgi/edithtml.py16
-rw-r--r--Mailman/Cgi/listinfo.py20
-rw-r--r--Mailman/Cgi/options.py22
-rw-r--r--Mailman/Cgi/private.py11
-rw-r--r--Mailman/Cgi/rmlist.py31
-rw-r--r--Mailman/Cgi/roster.py16
-rw-r--r--Mailman/Cgi/subscribe.py24
-rw-r--r--Mailman/Defaults.py.in10
-rw-r--r--Mailman/Deliverer.py19
-rw-r--r--Mailman/Gui/Language.py11
-rw-r--r--Mailman/Gui/Topics.py1
-rw-r--r--Mailman/Handlers/CalcRecips.py19
-rw-r--r--Mailman/Handlers/Cleanse.py10
-rw-r--r--Mailman/Handlers/CookHeaders.py1
-rw-r--r--Mailman/Handlers/Decorate.py17
-rw-r--r--Mailman/Handlers/Hold.py28
-rw-r--r--Mailman/Handlers/MimeDel.py16
-rw-r--r--Mailman/Handlers/Moderate.py14
-rw-r--r--Mailman/Handlers/Replybot.py18
-rw-r--r--Mailman/Handlers/SMTPDirect.py42
-rw-r--r--Mailman/Handlers/Scrubber.py9
-rw-r--r--Mailman/Handlers/Tagger.py18
-rw-r--r--Mailman/Handlers/ToDigest.py10
-rw-r--r--Mailman/Handlers/ToUsenet.py21
-rw-r--r--Mailman/ListAdmin.py22
-rw-r--r--Mailman/Logging/Logger.py104
-rw-r--r--Mailman/Logging/Makefile.in70
-rw-r--r--Mailman/Logging/MultiLogger.py76
-rw-r--r--Mailman/Logging/StampedLogger.py89
-rw-r--r--Mailman/Logging/Syslog.py76
-rw-r--r--Mailman/Logging/Utils.py52
-rw-r--r--Mailman/Logging/__init__.py15
-rw-r--r--Mailman/MTA/Postfix.py16
-rw-r--r--Mailman/MailList.py74
-rw-r--r--Mailman/Queue/BounceRunner.py34
-rw-r--r--Mailman/Queue/CommandRunner.py16
-rw-r--r--Mailman/Queue/IncomingRunner.py19
-rw-r--r--Mailman/Queue/MaildirRunner.py19
-rw-r--r--Mailman/Queue/NewsRunner.py15
-rw-r--r--Mailman/Queue/OutgoingRunner.py10
-rw-r--r--Mailman/Queue/Runner.py23
-rw-r--r--Mailman/Queue/Switchboard.py3
-rw-r--r--Mailman/SafeDict.py24
-rw-r--r--Mailman/SecurityManager.py14
-rw-r--r--Mailman/Utils.py10
-rw-r--r--Mailman/loginit.py88
-rw-r--r--Mailman/versions.py14
-rw-r--r--Makefile.in2
-rw-r--r--bin/qrunner39
-rwxr-xr-xconfigure5
-rw-r--r--configure.in6
-rw-r--r--scripts/driver121
63 files changed, 640 insertions, 991 deletions
diff --git a/Mailman/Archiver/Archiver.py b/Mailman/Archiver/Archiver.py
index 0a680fb0f..0089ee4dc 100644
--- a/Mailman/Archiver/Archiver.py
+++ b/Mailman/Archiver/Archiver.py
@@ -25,6 +25,7 @@ archival.
import os
import re
import errno
+import logging
import traceback
from cStringIO import StringIO
@@ -34,9 +35,10 @@ from Mailman import Utils
from Mailman import mm_cfg
from Mailman import Mailbox
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
from Mailman.SafeDict import SafeDict
+log = logging.getLogger('mailman.error')
+
def makelink(old, new):
@@ -165,7 +167,7 @@ class Archiver:
mbox.AppendMessage(post)
mbox.fp.close()
except IOError, msg:
- syslog('error', 'Archive file access failure:\n\t%s %s', afn, msg)
+ log.error('Archive file access failure:\n\t%s %s', afn, msg)
raise
def ExternalArchive(self, ar, txt):
@@ -177,8 +179,8 @@ class Archiver:
extarch.write(txt)
status = extarch.close()
if status:
- syslog('error', 'external archiver non-zero exit status: %d\n',
- (status & 0xff00) >> 8)
+ log.error('external archiver non-zero exit status: %d\n',
+ (status & 0xff00) >> 8)
#
# archiving in real time this is called from list.post(msg)
diff --git a/Mailman/Archiver/HyperArch.py b/Mailman/Archiver/HyperArch.py
index 3c5e7c1d6..e38d35e16 100644
--- a/Mailman/Archiver/HyperArch.py
+++ b/Mailman/Archiver/HyperArch.py
@@ -33,6 +33,7 @@ import time
import errno
import types
import urllib
+import logging
import weakref
import binascii
@@ -48,10 +49,10 @@ from Mailman import LockFile
from Mailman import MailList
from Mailman.Archiver import HyperDatabase
from Mailman.Archiver import pipermail
-from Mailman.Logging.Syslog import syslog
from Mailman.Mailbox import ArchiverMailbox
from Mailman.SafeDict import SafeDict
+log = logging.getLogger('mailman.error')
# Set up i18n. Assume the current language has already been set in the caller.
_ = i18n._
@@ -329,7 +330,7 @@ class Article(pipermail.Article):
try:
mlist = MailList.MailList(listname, lock=0)
except Errors.MMListError, e:
- syslog('error', 'error opening list: %s\n%s', listname, e)
+ log.error('error opening list: %s\n%s', listname, e)
return None
else:
self._listcache[listname] = mlist
@@ -854,10 +855,9 @@ class HyperArchive(pipermail.T):
# crashed during archiving. Save it, log an error, and move on.
try:
wf = open(wname)
- syslog('error',
- 'Archive working file %s present. '
- 'Check %s for possibly unarchived msgs',
- wname, ename)
+ log.error('Archive working file %s present. '
+ 'Check %s for possibly unarchived msgs',
+ wname, ename)
omask = os.umask(007)
try:
ef = open(ename, 'a+')
diff --git a/Mailman/Archiver/pipermail.py b/Mailman/Archiver/pipermail.py
index ce23ec222..1483b5c97 100644
--- a/Mailman/Archiver/pipermail.py
+++ b/Mailman/Archiver/pipermail.py
@@ -4,6 +4,7 @@ import os
import re
import sys
import time
+import logging
import mailbox
import cPickle as pickle
@@ -17,12 +18,13 @@ VERSION = __version__
CACHESIZE = 100 # Number of slots in the cache
from Mailman import Errors
-from Mailman.Logging.Syslog import syslog
from Mailman.Mailbox import ArchiverMailbox
from Mailman.i18n import _
SPACE = ' '
+log = logging.getLogger('mailman.error')
+
msgid_pat = re.compile(r'(<.*>)')
@@ -558,8 +560,7 @@ class T:
except Errors.DiscardMessage:
continue
except Exception:
- syslog('error', 'uncaught archiver exception at filepos: %s',
- pos)
+ log.error('uncaught archiver exception at filepos: %s', pos)
raise
if m is None:
break
diff --git a/Mailman/BDBMemberAdaptor.py b/Mailman/BDBMemberAdaptor.py
index 75424aba2..4cd8eaf30 100644
--- a/Mailman/BDBMemberAdaptor.py
+++ b/Mailman/BDBMemberAdaptor.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2003 by the Free Software Foundation, Inc.
+# Copyright (C) 2003-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
@@ -45,7 +45,6 @@ from Mailman import Utils
from Mailman import Errors
from Mailman import MemberAdaptor
from Mailman.MailList import MailList
-from Mailman.Logging.Syslog import syslog
STORAGE_VERSION = 'BA01'
FMT = '>BHB'
diff --git a/Mailman/Bouncer.py b/Mailman/Bouncer.py
index ce647a1db..caa4e0bb1 100644
--- a/Mailman/Bouncer.py
+++ b/Mailman/Bouncer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2005 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
@@ -19,18 +19,18 @@
import sys
import time
-from types import StringType
+import logging
-from email.MIMEText import MIMEText
from email.MIMEMessage import MIMEMessage
+from email.MIMEText import MIMEText
+from types import StringType
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import Message
from Mailman import MemberAdaptor
+from Mailman import Message
from Mailman import Pending
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
from Mailman import i18n
+from Mailman import mm_cfg
EMPTYSTRING = ''
@@ -49,6 +49,9 @@ REASONS = {MemberAdaptor.BYBOUNCE: _('due to excessive bounces'),
_ = i18n._
+log = logging.getLogger('mailman.bounce')
+slog = logging.getLogger('mailman.subscribe')
+
class _BounceInfo:
@@ -114,21 +117,21 @@ class Bouncer:
info = _BounceInfo(member, weight, day,
self.bounce_you_are_disabled_warnings)
self.setBounceInfo(member, info)
- syslog('bounce', '%s: %s bounce score: %s', self.internal_name(),
- member, info.score)
+ log.info('%s: %s bounce score: %s', self.internal_name(),
+ member, info.score)
# Continue to the check phase below
elif self.getDeliveryStatus(member) <> MemberAdaptor.ENABLED:
# The user is already disabled, so we can just ignore subsequent
# bounces. These are likely due to residual messages that were
# sent before disabling the member, but took a while to bounce.
- syslog('bounce', '%s: %s residual bounce received',
- self.internal_name(), member)
+ log.info('%s: %s residual bounce received',
+ self.internal_name(), member)
return
elif info.date == day:
# We've already scored any bounces for this day, so ignore it.
- syslog('bounce', '%s: %s already scored a bounce for date %s',
- self.internal_name(), member,
- time.strftime('%d-%b-%Y', day + (0,0,0,0,1,0)))
+ log.info('%s: %s already scored a bounce for date %s',
+ self.internal_name(), member,
+ time.strftime('%d-%b-%Y', day + (0,0,0,0,1,0)))
# Continue to check phase below
else:
# See if this member's bounce information is stale.
@@ -137,25 +140,24 @@ class Bouncer:
if lastbounce + self.bounce_info_stale_after < now:
# Information is stale, so simply reset it
info.reset(weight, day, self.bounce_you_are_disabled_warnings)
- syslog('bounce', '%s: %s has stale bounce info, resetting',
- self.internal_name(), member)
+ log.info('%s: %s has stale bounce info, resetting',
+ self.internal_name(), member)
else:
# Nope, the information isn't stale, so add to the bounce
# score and take any necessary action.
info.score += weight
info.date = day
- syslog('bounce', '%s: %s current bounce score: %s',
- self.internal_name(), member, info.score)
+ log.info('%s: %s current bounce score: %s',
+ self.internal_name(), member, info.score)
# Continue to the check phase below
#
# Now that we've adjusted the bounce score for this bounce, let's
# check to see if the disable-by-bounce threshold has been reached.
if info.score >= self.bounce_score_threshold:
if mm_cfg.VERP_PROBES:
- syslog('bounce',
- 'sending %s list probe to: %s (score %s >= %s)',
- self.internal_name(), member, info.score,
- self.bounce_score_threshold)
+ log.info('sending %s list probe to: %s (score %s >= %s)',
+ self.internal_name(), member, info.score,
+ self.bounce_score_threshold)
self.sendProbe(member, msg)
info.reset(0, info.date, info.noticesleft)
else:
@@ -168,12 +170,12 @@ class Bouncer:
info.cookie = cookie
# Disable them
if mm_cfg.VERP_PROBES:
- syslog('bounce', '%s: %s disabling due to probe bounce received',
- self.internal_name(), member)
+ log.info('%s: %s disabling due to probe bounce received',
+ self.internal_name(), member)
else:
- syslog('bounce', '%s: %s disabling due to bounce score %s >= %s',
- self.internal_name(), member,
- info.score, self.bounce_score_threshold)
+ log.info('%s: %s disabling due to bounce score %s >= %s',
+ self.internal_name(), member,
+ info.score, self.bounce_score_threshold)
self.setDeliveryStatus(member, MemberAdaptor.BYBOUNCE)
self.sendNextNotification(member)
if self.bounce_notify_owner_on_disable:
@@ -226,14 +228,14 @@ class Bouncer:
# returned data.
self.pend_confirm(info.cookie)
if reason == MemberAdaptor.BYBOUNCE:
- syslog('bounce', '%s: %s deleted after exhausting notices',
- self.internal_name(), member)
- syslog('subscribe', '%s: %s auto-unsubscribed [reason: %s]',
- self.internal_name(), member,
- {MemberAdaptor.BYBOUNCE: 'BYBOUNCE',
- MemberAdaptor.BYUSER: 'BYUSER',
- MemberAdaptor.BYADMIN: 'BYADMIN',
- MemberAdaptor.UNKNOWN: 'UNKNOWN'}.get(
+ log.info('%s: %s deleted after exhausting notices',
+ self.internal_name(), member)
+ slog.info('%s: %s auto-unsubscribed [reason: %s]',
+ self.internal_name(), member,
+ {MemberAdaptor.BYBOUNCE: 'BYBOUNCE',
+ MemberAdaptor.BYUSER: 'BYUSER',
+ MemberAdaptor.BYADMIN: 'BYADMIN',
+ MemberAdaptor.UNKNOWN: 'UNKNOWN'}.get(
reason, 'invalid value'))
return
# Send the next notification
diff --git a/Mailman/Bouncers/BouncerAPI.py b/Mailman/Bouncers/BouncerAPI.py
index e19c53f7e..2684af6b5 100644
--- a/Mailman/Bouncers/BouncerAPI.py
+++ b/Mailman/Bouncers/BouncerAPI.py
@@ -20,20 +20,15 @@
This module can also be used as the basis for a bounce detection testing
framework. When run as a script, it expects two arguments, the listname and
the filename containing the bounce message.
-
"""
import sys
-from Mailman.Logging.Syslog import syslog
-
# If a bounce detector returns Stop, that means to just discard the message.
# An example is warning messages for temporary delivery problems. These
# shouldn't trigger a bounce notification, but we also don't want to send them
# on to the list administrator.
-class _Stop:
- pass
-Stop = _Stop()
+Stop = object()
BOUNCE_PIPELINE = [
diff --git a/Mailman/Cgi/__init__.py b/Mailman/Cgi/__init__.py
index f569e43f4..e69de29bb 100644
--- a/Mailman/Cgi/__init__.py
+++ b/Mailman/Cgi/__init__.py
@@ -1,15 +0,0 @@
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index c78a68ac1..74aba72fa 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -24,6 +24,7 @@ import sha
import sys
import signal
import urllib
+import logging
from email.Utils import unquote, parseaddr, formataddr
from string import lowercase, digits
@@ -38,7 +39,6 @@ from Mailman import Utils
from Mailman.Cgi import Auth
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
from Mailman.UserDesc import UserDesc
# Set up i18n
@@ -48,6 +48,8 @@ i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
NL = '\n'
OPTCOLUMNS = 11
+log = logging.getLogger('mailman.error')
+
def main():
@@ -65,8 +67,7 @@ def main():
# Avoid cross-site scripting attacks
safelistname = Utils.websafe(listname)
admin_overview(_('No such list <em>%(safelistname)s</em>'))
- syslog('error', 'admin.py access for non-existent list: %s',
- listname)
+ log.error('admin.py access for non-existent list: %s', listname)
return
# Now that we know what list has been requested, all subsequent admin
# pages are shown in that list's preferred language.
diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py
index 7f42c8acd..9add54e0c 100644
--- a/Mailman/Cgi/admindb.py
+++ b/Mailman/Cgi/admindb.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2005 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
@@ -17,27 +17,28 @@
"""Produce and process the pending-approval items for a list."""
-import sys
import os
import cgi
+import sys
+import time
+import email
import errno
import signal
-import email
-import time
+
from types import ListType
from urllib import quote_plus, unquote_plus
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
-from Mailman import Message
from Mailman import i18n
-from Mailman.Handlers.Moderate import ModeratedMemberPost
-from Mailman.ListAdmin import readMessage
+from Mailman import MailList
+from Mailman import Message
+from Mailman import mm_cfg
+from Mailman import Utils
+
from Mailman.Cgi import Auth
+from Mailman.Handlers.Moderate import ModeratedMemberPost
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
+from Mailman.ListAdmin import readMessage
EMPTYSTRING = ''
NL = '\n'
@@ -50,6 +51,8 @@ i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
EXCERPT_HEIGHT = 10
EXCERPT_WIDTH = 76
+log = logging.getLogger('mailman.error')
+
def helds_by_sender(mlist):
@@ -88,7 +91,7 @@ def main():
# Avoid cross-site scripting attacks
safelistname = Utils.websafe(listname)
handle_no_list(_('No such list <em>%(safelistname)s</em>'))
- syslog('error', 'No such list "%s": %s\n', listname, e)
+ log.error('No such list "%s": %s\n', listname, e)
return
# Now that we know which list to use, set the system's language to it.
diff --git a/Mailman/Cgi/confirm.py b/Mailman/Cgi/confirm.py
index c9f4135a1..352cb81ad 100644
--- a/Mailman/Cgi/confirm.py
+++ b/Mailman/Cgi/confirm.py
@@ -28,13 +28,14 @@ from Mailman import mm_cfg
from Mailman import Pending
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
from Mailman.UserDesc import UserDesc
# Set up i18n
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+
def main():
@@ -57,7 +58,7 @@ def main():
bad_confirmation(doc, _('No such list <em>%(safelistname)s</em>'))
doc.AddItem(MailmanLogo())
print doc.Format()
- syslog('error', 'No such list "%s": %s', listname, e)
+ log.error('No such list "%s": %s', listname, e)
return
# Set the language for the list
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py
index 0667ac3fb..0c517c2cd 100644
--- a/Mailman/Cgi/create.py
+++ b/Mailman/Cgi/create.py
@@ -22,6 +22,7 @@ import cgi
import sha
import sys
import signal
+import logging
from types import ListType
@@ -32,12 +33,13 @@ from Mailman import Message
from Mailman import mm_cfg
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
# Set up i18n
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+
def main():
@@ -52,7 +54,7 @@ def main():
doc.SetTitle(title)
doc.AddItem(
Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
- syslog('error', 'Bad URL specification: %s', parts)
+ log.error('Bad URL specification: %s', parts)
elif cgidata.has_key('doit'):
# We must be processing the list creation request
process_request(doc, cgidata)
diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py
index 9ec54ceff..b0275de75 100644
--- a/Mailman/Cgi/edithtml.py
+++ b/Mailman/Cgi/edithtml.py
@@ -18,21 +18,23 @@
"""Script which implements admin editing of the list's html templates."""
import os
+import re
import cgi
import errno
-import re
+import logging
-from Mailman import Utils
+from Mailman import Errors
+from Mailman import i18n
from Mailman import MailList
+from Mailman import Utils
+from Mailman.Cgi import Auth
from Mailman.htmlformat import *
from Mailman.HTMLFormatter import HTMLFormatter
-from Mailman import Errors
-from Mailman.Cgi import Auth
-from Mailman.Logging.Syslog import syslog
-from Mailman import i18n
_ = i18n._
+log = logging.getLogger('mailman.error')
+
def main():
@@ -69,7 +71,7 @@ def main():
safelistname = Utils.websafe(listname)
doc.AddItem(Header(2, _('No such list <em>%(safelistname)s</em>')))
print doc.Format()
- syslog('error', 'No such list "%s": %s', listname, e)
+ log.error('No such list "%s": %s', listname, e)
return
# Now that we have a valid list, set the language to its default
diff --git a/Mailman/Cgi/listinfo.py b/Mailman/Cgi/listinfo.py
index abbf570b9..fc96f5d29 100644
--- a/Mailman/Cgi/listinfo.py
+++ b/Mailman/Cgi/listinfo.py
@@ -1,4 +1,4 @@
-# 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
@@ -12,28 +12,30 @@
#
# 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.
-"""Produce listinfo page, primary web entry-point to mailing lists.
-"""
+"""Produce listinfo page, primary web entry-point to mailing lists."""
# No lock needed in this script, because we don't change data.
import os
import cgi
+import logging
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
from Mailman import i18n
+from Mailman import MailList
+from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
# Set up i18n
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+
def main():
@@ -49,7 +51,7 @@ def main():
# Avoid cross-site scripting attacks
safelistname = Utils.websafe(listname)
listinfo_overview(_('No such list <em>%(safelistname)s</em>'))
- syslog('error', 'No such list "%s": %s', listname, e)
+ log.error('No such list "%s": %s', listname, e)
return
# See if the user want to see this page in other language
diff --git a/Mailman/Cgi/options.py b/Mailman/Cgi/options.py
index 98e1ae958..b2d63735f 100644
--- a/Mailman/Cgi/options.py
+++ b/Mailman/Cgi/options.py
@@ -22,6 +22,7 @@ import cgi
import sys
import signal
import urllib
+import logging
from types import ListType
@@ -33,7 +34,6 @@ from Mailman import mm_cfg
from Mailman import Utils
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
SLASH = '/'
SETLANGUAGE = -1
@@ -42,6 +42,9 @@ SETLANGUAGE = -1
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+mlog = logging.getLogger('mailman.mischief')
+
def main():
@@ -75,7 +78,7 @@ def main():
doc.AddItem('<hr>')
doc.AddItem(MailmanLogo())
print doc.Format()
- syslog('error', 'No such list "%s": %s\n', listname, e)
+ log.error('No such list "%s": %s\n', listname, e)
return
# The total contents of the user's response
@@ -183,9 +186,8 @@ def main():
# Public rosters
doc.addError(_('No such member: %(safeuser)s.'))
else:
- syslog('mischief',
- 'Unsub attempt of non-member w/ private rosters: %s',
- user)
+ mlog.error('Unsub attempt of non-member w/ private rosters: %s',
+ user)
doc.addError(_('The confirmation email has been sent.'),
tag='')
loginpage(mlist, doc, user, language)
@@ -205,9 +207,9 @@ def main():
# Public rosters
doc.addError(_('No such member: %(safeuser)s.'))
else:
- syslog('mischief',
- 'Reminder attempt of non-member w/ private rosters: %s',
- user)
+ mlog.error(
+ 'Reminder attempt of non-member w/ private rosters: %s',
+ user)
doc.addError(
_('A reminder of your password has been emailed to you.'),
tag='')
@@ -242,9 +244,7 @@ def main():
# So as not to allow membership leakage, prompt for the email
# address and the password here.
if mlist.private_roster <> 0:
- syslog('mischief',
- 'Login failure with private rosters: %s',
- user)
+ mlog.error('Login failure with private rosters: %s', user)
user = None
loginpage(mlist, doc, user, language)
print doc.Format()
diff --git a/Mailman/Cgi/private.py b/Mailman/Cgi/private.py
index 866084187..e71f878fc 100644
--- a/Mailman/Cgi/private.py
+++ b/Mailman/Cgi/private.py
@@ -20,6 +20,7 @@
import os
import sys
import cgi
+import logging
import mimetypes
from Mailman import mm_cfg
@@ -28,7 +29,6 @@ from Mailman import MailList
from Mailman import Errors
from Mailman import i18n
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
# Set up i18n. Until we know which list is being requested, we use the
# server's default.
@@ -37,6 +37,9 @@ i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
SLASH = '/'
+log = logging.getLogger('mailman.error')
+mlog = logging.getLogger('mailman.mischief')
+
def true_path(path):
@@ -73,7 +76,7 @@ def main():
doc.SetTitle(msg)
doc.AddItem(Header(2, msg))
print doc.Format()
- syslog('mischief', 'Private archive hostile path: %s', path)
+ mlog.error('Private archive hostile path: %s', path)
return
# BAW: This needs to be converted to the Site module abstraction
true_filename = os.path.join(
@@ -109,7 +112,7 @@ def main():
doc.SetTitle(_("Private Archive Error - %(msg)s"))
doc.AddItem(Header(2, msg))
print doc.Format()
- syslog('error', 'No such list "%s": %s\n', listname, e)
+ log.error('No such list "%s": %s\n', listname, e)
return
i18n.set_language(mlist.preferred_language)
@@ -180,7 +183,7 @@ def main():
doc.SetTitle(msg)
doc.AddItem(Header(2, msg))
print doc.Format()
- syslog('error', 'Private archive file not found: %s', true_filename)
+ log.error('Private archive file not found: %s', true_filename)
else:
print 'Content-type: %s\n' % ctype
sys.stdout.write(f.read())
diff --git a/Mailman/Cgi/rmlist.py b/Mailman/Cgi/rmlist.py
index 4628f5fd3..78a3e0a12 100644
--- a/Mailman/Cgi/rmlist.py
+++ b/Mailman/Cgi/rmlist.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001,2002 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
@@ -12,7 +12,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.
"""Remove/delete mailing lists through the web."""
@@ -21,19 +22,22 @@ import cgi
import sys
import errno
import shutil
+import logging
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
from Mailman import i18n
+from Mailman import MailList
+from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
# Set up i18n
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+mlog = logging.getLogger('mailman.mischief')
+
def main():
@@ -52,7 +56,7 @@ def main():
doc.AddItem('<hr>')
doc.AddItem(MailmanLogo())
print doc.Format()
- syslog('error', 'Bad URL specification: %s', parts)
+ log.error('Bad URL specification: %s', parts)
return
listname = parts[0].lower()
@@ -69,7 +73,7 @@ def main():
doc.AddItem('<hr>')
doc.AddItem(MailmanLogo())
print doc.Format()
- syslog('error', 'No such list "%s": %s\n', listname, e)
+ log.error('No such list "%s": %s\n', listname, e)
return
# Now that we have a valid mailing list, set the language
@@ -84,7 +88,7 @@ def main():
Header(3, Bold(FontAttr(title, color='#ff0000', size='+2'))))
doc.AddItem(mlist.GetMailmanFooter())
print doc.Format()
- syslog('mischief', 'Attempt to sneakily delete a list: %s', listname)
+ mlog.error('Attempt to sneakily delete a list: %s', listname)
return
if cgidata.has_key('doit'):
@@ -144,18 +148,15 @@ def process_request(doc, cgidata, mlist):
except OSError, e:
if e.errno not in (errno.EACCES, errno.EPERM): raise
problems += 1
- syslog('error',
- 'link %s not deleted due to permission problems',
- dir)
+ log.error('link %s not deleted due to permission problems', dir)
elif os.path.isdir(dir):
try:
shutil.rmtree(dir)
except OSError, e:
if e.errno not in (errno.EACCES, errno.EPERM): raise
problems += 1
- syslog('error',
- 'directory %s not deleted due to permission problems',
- dir)
+ log.error('directory %s not deleted due to permission problems',
+ dir)
title = _('Mailing list deletion results')
doc.SetTitle(title)
diff --git a/Mailman/Cgi/roster.py b/Mailman/Cgi/roster.py
index a67e51002..0ce590398 100644
--- a/Mailman/Cgi/roster.py
+++ b/Mailman/Cgi/roster.py
@@ -1,4 +1,4 @@
-# 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
@@ -23,23 +23,25 @@ Takes listname in PATH_INFO.
# We don't need to lock in this script, because we're never going to change
# data.
-import sys
import os
import cgi
+import sys
import urllib
+import logging
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
from Mailman import i18n
+from Mailman import MailList
+from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
# Set up i18n
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+
def main():
@@ -55,7 +57,7 @@ def main():
# Avoid cross-site scripting attacks
safelistname = Utils.websafe(listname)
error_page(_('No such list <em>%(safelistname)s</em>'))
- syslog('error', 'roster: no such list "%s": %s', listname, e)
+ log.error('roster: no such list "%s": %s', listname, e)
return
cgidata = cgi.FieldStorage()
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py
index 3661dcde5..6aee0e6f8 100644
--- a/Mailman/Cgi/subscribe.py
+++ b/Mailman/Cgi/subscribe.py
@@ -1,4 +1,4 @@
-# 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
@@ -12,24 +12,25 @@
#
# 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 subscription or roster requests from listinfo form."""
-import sys
import os
import cgi
+import sys
import signal
+import logging
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
from Mailman import Errors
from Mailman import i18n
+from Mailman import MailList
from Mailman import Message
-from Mailman.UserDesc import UserDesc
+from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.htmlformat import *
-from Mailman.Logging.Syslog import syslog
+from Mailman.UserDesc import UserDesc
SLASH = '/'
ERRORSEP = '\n\n<p>'
@@ -38,6 +39,9 @@ ERRORSEP = '\n\n<p>'
_ = i18n._
i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+log = logging.getLogger('mailman.error')
+mlog = logging.getLogger('mailman.mischief')
+
def main():
@@ -60,7 +64,7 @@ def main():
doc.AddItem(Header(2, _("Error")))
doc.AddItem(Bold(_('No such list <em>%(safelistname)s</em>')))
print doc.Format()
- syslog('error', 'No such list "%s": %s\n', listname, e)
+ log.error('No such list "%s": %s\n', listname, e)
return
# See if the form data has a preferred language set, in which case, use it
@@ -119,7 +123,7 @@ def process_form(mlist, doc, cgidata, lang):
'unidentified origin'))
# Was an attempt made to subscribe the list to itself?
if email == mlist.GetListEmail():
- syslog('mischief', 'Attempt to self subscribe %s: %s', email, remote)
+ mlog.error('Attempt to self subscribe %s: %s', email, remote)
results.append(_('You may not subscribe a list to itself!'))
# If the user did not supply a password, generate one for him
password = cgidata.getvalue('pw')
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index be7a3c616..97e262ddc 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -495,7 +495,7 @@ OWNER_PIPELINE = [
]
-# This defines syslog() format strings for the SMTPDirect delivery module (see
+# This defines log format strings for the SMTPDirect delivery module (see
# DELIVERY_MODULE above). Valid %()s string substitutions include:
#
# time -- the time in float seconds that it took to complete the smtp
@@ -524,10 +524,10 @@ OWNER_PIPELINE = [
# below.
#
# The format of the entries is a 2-tuple with the first element naming the
-# file in logs/ to print the message to, and the second being a format string
-# appropriate for Python's %-style string interpolation. The file name is
-# arbitrary; qfiles/<name> will be created automatically if it does not
-# exist.
+# logger (as a child of the root 'mailman' logger) to print the message to,
+# and the second being a format string appropriate for Python's %-style string
+# interpolation. The file name is arbitrary; qfiles/<name> will be created
+# automatically if it does not exist.
# The format of the message printed for every delivered message, regardless of
# whether the delivery was successful or not. Set to None to disable the
diff --git a/Mailman/Deliverer.py b/Mailman/Deliverer.py
index 63f98db73..e1007e135 100644
--- a/Mailman/Deliverer.py
+++ b/Mailman/Deliverer.py
@@ -18,20 +18,23 @@
"""Mixin class with message delivery routines."""
-from email.MIMEText import MIMEText
+import logging
+
from email.MIMEMessage import MIMEMessage
+from email.MIMEText import MIMEText
from Mailman import i18n
from Mailman import Errors
from Mailman import Message
from Mailman import mm_cfg
-from Mailman import Utils
from Mailman import Pending
-
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
_ = i18n._
+log = logging.getLogger('mailman.error')
+mlog = logging.getLogger('mailman.mischief')
+
class Deliverer:
@@ -93,8 +96,8 @@ your membership administrative address, %(addr)s.'''))
if not self.getMemberPassword(user):
# The user's password somehow got corrupted. Generate a new one
# for him, after logging this bogosity.
- syslog('error', 'User %s had a false password for list %s',
- user, self.internal_name())
+ log.error('User %s had a false password for list %s',
+ user, self.internal_name())
waslocked = self.Locked()
if not waslocked:
self.Lock()
@@ -154,8 +157,8 @@ your membership administrative address, %(addr)s.'''))
# list. We inform both list owners of the bogosity, but be careful
# not to reveal too much information.
selfname = self.internal_name()
- syslog('mischief', '%s was invited to %s but confirmed to %s',
- address, listname, selfname)
+ mlog.error('%s was invited to %s but confirmed to %s',
+ address, listname, selfname)
# First send a notice to the attacked list
msg = Message.OwnerNotification(
self,
diff --git a/Mailman/Gui/Language.py b/Mailman/Gui/Language.py
index e9400fca3..65fe4c4a6 100644
--- a/Mailman/Gui/Language.py
+++ b/Mailman/Gui/Language.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001,2002 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
@@ -12,17 +12,16 @@
#
# 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.
-"""MailList mixin class managing the language options.
-"""
+"""MailList mixin class managing the language options."""
import codecs
+from Mailman import i18n
from Mailman import mm_cfg
from Mailman import Utils
-from Mailman import i18n
-from Mailman.Logging.Syslog import syslog
from Mailman.Gui.GUIBase import GUIBase
_ = i18n._
diff --git a/Mailman/Gui/Topics.py b/Mailman/Gui/Topics.py
index 5e250b245..282930b7c 100644
--- a/Mailman/Gui/Topics.py
+++ b/Mailman/Gui/Topics.py
@@ -20,7 +20,6 @@ import re
from Mailman import mm_cfg
from Mailman import Utils
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
from Mailman.Gui.GUIBase import GUIBase
diff --git a/Mailman/Handlers/CalcRecips.py b/Mailman/Handlers/CalcRecips.py
index e065ad686..e5acd23fb 100644
--- a/Mailman/Handlers/CalcRecips.py
+++ b/Mailman/Handlers/CalcRecips.py
@@ -1,18 +1,19 @@
-# Copyright (C) 1998,1999,2000,2001,2002 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
# 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.
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
"""Calculate the regular (i.e. non-digest) recipients of the message.
@@ -22,13 +23,12 @@ on the `recips' attribute of the message. This attribute is used by the
SendmailDeliver and BulkDeliver modules.
"""
+from Mailman import Errors
+from Mailman import Message
from Mailman import mm_cfg
from Mailman import Utils
-from Mailman import Message
-from Mailman import Errors
-from Mailman.MemberAdaptor import ENABLED
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
+from Mailman.MemberAdaptor import ENABLED
@@ -130,4 +130,3 @@ def do_topic_filters(mlist, msg, msgdata, recips):
# Prune out the non-receiving users
for user in zaprecips:
recips.remove(user)
-
diff --git a/Mailman/Handlers/Cleanse.py b/Mailman/Handlers/Cleanse.py
index 8033d41f3..14c0e583c 100644
--- a/Mailman/Handlers/Cleanse.py
+++ b/Mailman/Handlers/Cleanse.py
@@ -17,12 +17,16 @@
"""Cleanse certain headers from all messages."""
+import logging
+
from email.Utils import formataddr
-from Mailman.Logging.Syslog import syslog
from Mailman.Handlers.CookHeaders import uheader
+log = logging.getLogger('mailman.post')
+
+
def process(mlist, msg, msgdata):
# Always remove this header from any outgoing messages. Be sure to do
# this after the information on the header is actually used, but before a
@@ -34,8 +38,8 @@ def process(mlist, msg, msgdata):
del msg['urgent']
# We remove other headers from anonymous lists
if mlist.anonymous_list:
- syslog('post', 'post to %s from %s anonymized',
- mlist.internal_name(), msg.get('from'))
+ log.info('post to %s from %s anonymized',
+ mlist.internal_name(), msg.get('from'))
del msg['from']
del msg['reply-to']
del msg['sender']
diff --git a/Mailman/Handlers/CookHeaders.py b/Mailman/Handlers/CookHeaders.py
index d85b9b877..458f9d362 100644
--- a/Mailman/Handlers/CookHeaders.py
+++ b/Mailman/Handlers/CookHeaders.py
@@ -28,7 +28,6 @@ from email.Utils import parseaddr, formataddr, getaddresses
from Mailman import mm_cfg
from Mailman import Utils
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
CONTINUATION = ',\n\t'
COMMASPACE = ', '
diff --git a/Mailman/Handlers/Decorate.py b/Mailman/Handlers/Decorate.py
index 09b6d6c1d..770114a49 100644
--- a/Mailman/Handlers/Decorate.py
+++ b/Mailman/Handlers/Decorate.py
@@ -17,22 +17,19 @@
"""Decorate a message by sticking the header and footer around it."""
-from types import ListType
+import logging
+
from email.MIMEText import MIMEText
+from types import ListType
+from Mailman import Errors
from Mailman import mm_cfg
from Mailman import Utils
-from Mailman import Errors
-from Mailman.Message import Message
from Mailman.i18n import _
+from Mailman.Message import Message
from Mailman.SafeDict import SafeDict
-from Mailman.Logging.Syslog import syslog
-try:
- True, False
-except:
- True = 1
- False = 0
+log = logging.getLogger('mailman.error')
@@ -213,7 +210,7 @@ def decorate(mlist, template, what, extradict={}):
try:
text = (template % d).replace('\r\n', '\n')
except (ValueError, TypeError), e:
- syslog('error', 'Exception while calculating %s:\n%s', what, e)
+ log.error('Exception while calculating %s:\n%s', what, e)
what = what.upper()
text = template
return text
diff --git a/Mailman/Handlers/Hold.py b/Mailman/Handlers/Hold.py
index fdfaa09d2..a044b67ee 100644
--- a/Mailman/Handlers/Hold.py
+++ b/Mailman/Handlers/Hold.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2005 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
@@ -12,7 +12,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.
"""Determine whether this message should be held for approval.
@@ -28,21 +29,24 @@ message handling should stop.
"""
import email
-from email.MIMEText import MIMEText
-from email.MIMEMessage import MIMEMessage
+import logging
import email.Utils
+
+from email.MIMEMessage import MIMEMessage
+from email.MIMEText import MIMEText
from types import ClassType
-from Mailman import mm_cfg
-from Mailman import Utils
from Mailman import Errors
-from Mailman import Message
from Mailman import i18n
+from Mailman import mm_cfg
+from Mailman import Message
from Mailman import Pending
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
+
+log = logging.getLogger('mailman.vette')
-# First, play footsie with _ so that the following are marked as translated,
-# but aren't actually translated until we need the text later on.
+# Play footsie with _ so that the following are marked as translated, but
+# aren't actually translated until we need the text later on.
def _(s):
return s
@@ -284,8 +288,8 @@ also appear in the first line of the body of the reply.""")),
finally:
i18n.set_translation(otranslation)
# Log the held message
- syslog('vette', '%s post from %s held, message-id=%s: %s',
- listname, sender, message_id, reason)
+ log.info('%s post from %s held, message-id=%s: %s',
+ listname, sender, message_id, reason)
# raise the specific MessageHeld exception to exit out of the message
# delivery pipeline
raise exc
diff --git a/Mailman/Handlers/MimeDel.py b/Mailman/Handlers/MimeDel.py
index 906b12c3d..5533f54e3 100644
--- a/Mailman/Handlers/MimeDel.py
+++ b/Mailman/Handlers/MimeDel.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2005 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-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
@@ -26,19 +26,21 @@ contents.
import os
import errno
+import logging
import tempfile
-from os.path import splitext
from email.Iterators import typed_subpart_iterator
+from os.path import splitext
-from Mailman import mm_cfg
from Mailman import Errors
+from Mailman import mm_cfg
+from Mailman.i18n import _
from Mailman.Message import UserNotification
from Mailman.Queue.sbcache import get_switchboard
-from Mailman.Logging.Syslog import syslog
-from Mailman.Version import VERSION
-from Mailman.i18n import _
from Mailman.Utils import oneline
+from Mailman.Version import VERSION
+
+log = logging.getLogger('mailman.error')
@@ -204,7 +206,7 @@ def to_plaintext(msg):
plaintext = cmd.read()
rtn = cmd.close()
if rtn:
- syslog('error', 'HTML->text/plain error: %s', rtn)
+ log.error('HTML->text/plain error: %s', rtn)
finally:
try:
os.unlink(filename)
diff --git a/Mailman/Handlers/Moderate.py b/Mailman/Handlers/Moderate.py
index 97d998b24..b96bd84e8 100644
--- a/Mailman/Handlers/Moderate.py
+++ b/Mailman/Handlers/Moderate.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001-2003 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
@@ -12,22 +12,22 @@
#
# 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.
-"""Posting moderation filter.
-"""
+"""Posting moderation filter."""
import re
+
from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
+from Mailman import Errors
+from Mailman import Message
from Mailman import mm_cfg
from Mailman import Utils
-from Mailman import Message
-from Mailman import Errors
from Mailman.i18n import _
from Mailman.Handlers import Hold
-from Mailman.Logging.Syslog import syslog
diff --git a/Mailman/Handlers/Replybot.py b/Mailman/Handlers/Replybot.py
index 6cd74ca88..43cf75402 100644
--- a/Mailman/Handlers/Replybot.py
+++ b/Mailman/Handlers/Replybot.py
@@ -1,4 +1,4 @@
-# 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
@@ -12,18 +12,20 @@
#
# 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.
-"""Handler for auto-responses.
-"""
+"""Handler for auto-responses."""
import time
+import logging
-from Mailman import Utils
from Mailman import Message
+from Mailman import Utils
from Mailman.i18n import _
from Mailman.SafeDict import SafeDict
-from Mailman.Logging.Syslog import syslog
+
+log = logging.getLogger('mailman.error')
@@ -97,8 +99,8 @@ def process(mlist, msg, msgdata):
try:
text = rtext % d
except Exception:
- syslog('error', 'Bad autoreply text for list: %s\n%s',
- mlist.internal_name(), rtext)
+ log.error('Bad autoreply text for list: %s\n%s',
+ mlist.internal_name(), rtext)
text = rtext
# Wrap the response.
text = Utils.wrap(text)
diff --git a/Mailman/Handlers/SMTPDirect.py b/Mailman/Handlers/SMTPDirect.py
index 702e78312..c68d269bf 100644
--- a/Mailman/Handlers/SMTPDirect.py
+++ b/Mailman/Handlers/SMTPDirect.py
@@ -30,22 +30,29 @@ import copy
import time
import email
import socket
+import logging
import smtplib
-from email.Utils import formataddr
-from email.Header import Header
from email.Charset import Charset
+from email.Header import Header
+from email.Utils import formataddr
from types import UnicodeType
from Mailman import Errors
from Mailman import mm_cfg
from Mailman import Utils
from Mailman.Handlers import Decorate
-from Mailman.Logging.Syslog import syslog
from Mailman.SafeDict import MsgSafeDict
DOT = '.'
+log = logging.getLogger('mailman.smtp')
+flog = logging.getLogger('mailman.smtp-failure')
+every_log = logging.getLogger('mailman.' + mm_cfg.SMTP_LOG_EVERY_MESSAGE[0])
+success_log = logging.getLogger('mailman.' + mm_cfg.SMTP_LOG_SUCCESS[0])
+refused_log = logging.getLogger('mailman.' + mm_cfg.SMTP_LOG_REFUSED[0])
+failure_log = logging.getLogger('mailman.' + mm_cfg.SMTP_LOG_EACH_FAILURE[0])
+
# Manage a connection to the SMTP server
@@ -173,17 +180,14 @@ def process(mlist, msg, msgdata):
'sender' : origsender,
})
# We have to use the copy() method because extended call syntax requires a
- # concrete dictionary object; it does not allow a generic mapping. It's
- # still worthwhile doing the interpolation in syslog() because it'll catch
- # any catastrophic exceptions due to bogus format strings.
+ # concrete dictionary object; it does not allow a generic mapping (XXX is
+ # this still true in Python 2.3?).
if mm_cfg.SMTP_LOG_EVERY_MESSAGE:
- syslog.write_ex(mm_cfg.SMTP_LOG_EVERY_MESSAGE[0],
- mm_cfg.SMTP_LOG_EVERY_MESSAGE[1], kws=d)
+ every_log.info('%s', mm_cfg.SMTP_LOG_EVERY_MESSAGE[1] % d)
if refused:
if mm_cfg.SMTP_LOG_REFUSED:
- syslog.write_ex(mm_cfg.SMTP_LOG_REFUSED[0],
- mm_cfg.SMTP_LOG_REFUSED[1], kws=d)
+ refused_log.info('%s', mm_cfg.SMTP_LOG_REFUSED[1] % d)
elif msgdata.get('tolist'):
# Log the successful post, but only if it really was a post to the
@@ -192,8 +196,7 @@ def process(mlist, msg, msgdata):
# the other messages, but in that case, we should probably have a
# separate configuration variable to control that.
if mm_cfg.SMTP_LOG_SUCCESS:
- syslog.write_ex(mm_cfg.SMTP_LOG_SUCCESS[0],
- mm_cfg.SMTP_LOG_SUCCESS[1], kws=d)
+ success_log.info('%s', mm_cfg.SMTP_LOG_SUCCESS[1] % d)
# Process any failed deliveries.
tempfailures = []
@@ -219,8 +222,7 @@ def process(mlist, msg, msgdata):
d.update({'recipient': recip,
'failcode' : code,
'failmsg' : smtpmsg})
- syslog.write_ex(mm_cfg.SMTP_LOG_EACH_FAILURE[0],
- mm_cfg.SMTP_LOG_EACH_FAILURE[1], kws=d)
+ failure_log.info('%s', mm_cfg.SMTP_LOG_EACH_FAILURE[1] % d)
# Return the results
if tempfailures or permfailures:
raise Errors.SomeRecipientsFailed(tempfailures, permfailures)
@@ -293,8 +295,7 @@ def verpdeliver(mlist, msg, msgdata, envsender, failures, conn):
# deliver it to this person, nor can we craft a valid verp
# header. I don't think there's much we can do except ignore
# this recipient.
- syslog('smtp', 'Skipping VERP delivery to unqual recip: %s',
- recip)
+ log.info('Skipping VERP delivery to unqual recip: %s', recip)
continue
d = {'bounces': bmailbox,
'mailbox': rmailbox,
@@ -362,12 +363,11 @@ def bulkdeliver(mlist, msg, msgdata, envsender, failures, conn):
# Send the message
refused = conn.sendmail(envsender, recips, msgtext)
except smtplib.SMTPRecipientsRefused, e:
- syslog('smtp-failure', 'All recipients refused: %s, msgid: %s',
- e, msgid)
+ flog.error('All recipients refused: %s, msgid: %s', e, msgid)
refused = e.recipients
except smtplib.SMTPResponseException, e:
- syslog('smtp-failure', 'SMTP session failure: %s, %s, msgid: %s',
- e.smtp_code, e.smtp_error, msgid)
+ flog.error('SMTP session failure: %s, %s, msgid: %s',
+ e.smtp_code, e.smtp_error, msgid)
# If this was a permanent failure, don't add the recipients to the
# refused, because we don't want them to be added to failures.
# Otherwise, if the MTA rejects the message because of the message
@@ -382,7 +382,7 @@ def bulkdeliver(mlist, msg, msgdata, envsender, failures, conn):
# MTA not responding, or other socket problems, or any other kind of
# SMTPException. In that case, nothing got delivered, so treat this
# as a temporary failure.
- syslog('smtp-failure', 'Low level smtp error: %s, msgid: %s', e, msgid)
+ flog.error('Low level smtp error: %s, msgid: %s', e, msgid)
error = str(e)
for r in recips:
refused[r] = (-1, error)
diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py
index 606338e95..a96bb0b39 100644
--- a/Mailman/Handlers/Scrubber.py
+++ b/Mailman/Handlers/Scrubber.py
@@ -22,6 +22,7 @@ import re
import sha
import time
import errno
+import logging
import binascii
import tempfile
@@ -40,7 +41,6 @@ from Mailman import LockFile
from Mailman import Utils
from Mailman.Errors import DiscardMessage
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
# Path characters for common platforms
pre = re.compile(r'[/\\:]')
@@ -53,6 +53,8 @@ dre = re.compile(r'^\.*')
BR = '<br>\n'
SPACE = ' '
+log = logging.getLogger('mailman.error')
+
def guess_extension(ctype, ext):
@@ -464,9 +466,8 @@ def save_attachment(mlist, msg, dir, filter_html=True):
decodedpayload = progfp.read()
status = progfp.close()
if status:
- syslog('error',
- 'HTML sanitizer exited with non-zero status: %s',
- status)
+ log.error('HTML sanitizer exited with non-zero status: %s',
+ status)
finally:
os.unlink(tmppath)
# BAW: Since we've now sanitized the document, it should be plain
diff --git a/Mailman/Handlers/Tagger.py b/Mailman/Handlers/Tagger.py
index 270f6611a..f384356d1 100644
--- a/Mailman/Handlers/Tagger.py
+++ b/Mailman/Handlers/Tagger.py
@@ -1,21 +1,21 @@
-# Copyright (C) 2001,2002 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
# 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.
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
-"""Extract topics from the original mail message.
-"""
+"""Extract topics from the original mail message."""
import re
import email
@@ -23,8 +23,6 @@ import email.Errors
import email.Iterators
import email.Parser
-from Mailman.Logging.Syslog import syslog
-
CRNL = '\r\n'
EMPTYSTRING = ''
NLTAB = '\n\t'
@@ -61,7 +59,7 @@ def process(mlist, msg, msgdata):
if hits:
msgdata['topichits'] = hits.keys()
msg['X-Topics'] = NLTAB.join(hits.keys())
-
+
def scanbody(msg, numlines=None):
diff --git a/Mailman/Handlers/ToDigest.py b/Mailman/Handlers/ToDigest.py
index 80bc2877e..21acb10c1 100644
--- a/Mailman/Handlers/ToDigest.py
+++ b/Mailman/Handlers/ToDigest.py
@@ -29,6 +29,7 @@ import os
import re
import copy
import time
+import logging
from cStringIO import StringIO
from email.Charset import Charset
@@ -42,13 +43,12 @@ from email.Utils import getaddresses, formatdate
from types import ListType
from Mailman import Errors
-from Mailman import Message
-from Mailman import Utils
from Mailman import i18n
+from Mailman import Message
from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.Handlers.Decorate import decorate
from Mailman.Handlers.Scrubber import process as scrubber
-from Mailman.Logging.Syslog import syslog
from Mailman.Mailbox import Mailbox
from Mailman.Mailbox import Mailbox
from Mailman.MemberAdaptor import ENABLED
@@ -59,6 +59,8 @@ _ = i18n._
UEMPTYSTRING = u''
EMPTYSTRING = ''
+log = logging.getLogger('mailman.error')
+
def process(mlist, msg, msgdata):
@@ -93,7 +95,7 @@ def process(mlist, msg, msgdata):
except Exception, errmsg:
# Bare except is generally prohibited in Mailman, but we can't
# forecast what exceptions can occur here.
- syslog('error', 'send_digests() failed: %s', errmsg)
+ log.error('send_digests() failed: %s', errmsg)
mboxfp.close()
diff --git a/Mailman/Handlers/ToUsenet.py b/Mailman/Handlers/ToUsenet.py
index 805d7f11d..b51c00a65 100644
--- a/Mailman/Handlers/ToUsenet.py
+++ b/Mailman/Handlers/ToUsenet.py
@@ -1,27 +1,32 @@
-# Copyright (C) 1998,1999,2000,2001,2002 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
# 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.
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
"""Move the message to the mail->news queue."""
+import logging
+
from Mailman import mm_cfg
from Mailman.Queue.sbcache import get_switchboard
-from Mailman.Logging.Syslog import syslog
COMMASPACE = ', '
+log = logging.getLogger('mailman.error')
+
+
def process(mlist, msg, msgdata):
# short circuits
@@ -36,8 +41,8 @@ def process(mlist, msg, msgdata):
if not mlist.nntp_host:
error.append('no NNTP host')
if error:
- syslog('error', 'NNTP gateway improperly configured: %s',
- COMMASPACE.join(error))
+ log.error('NNTP gateway improperly configured: %s',
+ COMMASPACE.join(error))
return
# Put the message in the news runner's queue
newsq = get_switchboard(mm_cfg.NEWSQUEUE_DIR)
diff --git a/Mailman/ListAdmin.py b/Mailman/ListAdmin.py
index f7035b5aa..2e8fc1a42 100644
--- a/Mailman/ListAdmin.py
+++ b/Mailman/ListAdmin.py
@@ -28,6 +28,7 @@ import time
import email
import errno
import cPickle
+import logging
import marshal
from cStringIO import StringIO
@@ -36,11 +37,10 @@ from email.MIMEMessage import MIMEMessage
from email.Utils import getaddresses
from Mailman import Errors
-from Mailman import Message
-from Mailman import Utils
from Mailman import i18n
+from Mailman import Message
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
from Mailman.Queue.sbcache import get_switchboard
from Mailman.UserDesc import UserDesc
@@ -60,6 +60,8 @@ LOST = 2
DASH = '-'
NL = '\n'
+log = logging.getLogger('mailman.vette')
+
class ListAdmin:
@@ -277,8 +279,8 @@ class ListAdmin:
# message directly here can lead to a huge delay in web
# turnaround. Log the moderation and add a header.
msg['X-Mailman-Approved-At'] = email.Utils.formatdate(localtime=1)
- syslog('vette', 'held message approved, message-id: %s',
- msg.get('message-id', 'n/a'))
+ log.info('held message approved, message-id: %s',
+ msg.get('message-id', 'n/a'))
# Stick the message back in the incoming queue for further
# processing.
inq = get_switchboard(mm_cfg.INQUEUE_DIR)
@@ -344,7 +346,7 @@ class ListAdmin:
}
if comment:
note += '\n\tReason: ' + comment.replace('%', '%%')
- syslog('vette', note)
+ log.info('%s', note)
# Always unlink the file containing the message text. It's not
# necessary anymore, regardless of the disposition of the message.
if status <> DEFER:
@@ -376,8 +378,8 @@ class ListAdmin:
#
# TBD: this really shouldn't go here but I'm not sure where else is
# appropriate.
- syslog('vette', '%s: held subscription request from %s',
- self.internal_name(), addr)
+ log.info('%s: held subscription request from %s',
+ self.internal_name(), addr)
# Possibly notify the administrator in default list language
if self.admin_immed_notify:
realname = self.real_name
@@ -428,8 +430,8 @@ class ListAdmin:
id = self.__nextid()
# All we need to do is save the unsubscribing address
self.__db[id] = (UNSUBSCRIPTION, addr)
- syslog('vette', '%s: held unsubscription request from %s',
- self.internal_name(), addr)
+ log.info('%s: held unsubscription request from %s',
+ self.internal_name(), addr)
# Possibly notify the administrator of the hold
if self.admin_immed_notify:
realname = self.real_name
diff --git a/Mailman/Logging/Logger.py b/Mailman/Logging/Logger.py
deleted file mode 100644
index 617347d49..000000000
--- a/Mailman/Logging/Logger.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (C) 1998-2005 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.
-
-"""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, 'replace')
- 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
deleted file mode 100644
index e185775fc..000000000
--- a/Mailman/Logging/Makefile.in
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 1998-2003 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.
-
-# 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@
-DESTDIR=
-
-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 $(DESTDIR)$(PACKAGEDIR); \
- done
-
-finish:
-
-clean:
-
-distclean:
- -rm *.pyc
- -rm Makefile
diff --git a/Mailman/Logging/MultiLogger.py b/Mailman/Logging/MultiLogger.py
deleted file mode 100644
index 7d9435e90..000000000
--- a/Mailman/Logging/MultiLogger.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
deleted file mode 100644
index ca313c537..000000000
--- a/Mailman/Logging/StampedLogger.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
deleted file mode 100644
index 531ab1d7b..000000000
--- a/Mailman/Logging/Syslog.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (C) 1998-2005 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.
-
-"""Central logging class for the Mailman system.
-
-This might eventually be replaced by a syslog based logger, hence the name.
-"""
-
-import quopri
-
-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)
- try:
- logf.write(msg + '\n')
- except UnicodeError:
- # Python 2.4 may fail to write 8bit (non-ascii) characters
- logf.write(quopri.encodestring(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
deleted file mode 100644
index 46bf487af..000000000
--- a/Mailman/Logging/Utils.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
deleted file mode 100644
index f569e43f4..000000000
--- a/Mailman/Logging/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/Mailman/MTA/Postfix.py b/Mailman/MTA/Postfix.py
index 172b22ea8..46143c549 100644
--- a/Mailman/MTA/Postfix.py
+++ b/Mailman/MTA/Postfix.py
@@ -22,20 +22,22 @@ import grp
import pwd
import time
import errno
+import logging
from stat import *
from Mailman import LockFile
-from Mailman import Utils
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
-from Mailman.MTA.Utils import makealiases
+from Mailman import Utils
from Mailman.i18n import _
+from Mailman.MTA.Utils import makealiases
LOCKFILE = os.path.join(mm_cfg.LOCK_DIR, 'creator')
ALIASFILE = os.path.join(mm_cfg.DATA_DIR, 'aliases')
VIRTFILE = os.path.join(mm_cfg.DATA_DIR, 'virtual-mailman')
+log = logging.getLogger('mailman.error')
+
def _update_maps():
@@ -44,15 +46,15 @@ def _update_maps():
status = (os.system(acmd) >> 8) & 0xff
if status:
errstr = os.strerror(status)
- syslog('error', msg, acmd, status, errstr)
- raise RuntimeError, msg % (acmd, status, errstr)
+ log.error(msg, acmd, status, errstr)
+ raise RuntimeError(msg % (acmd, status, errstr))
if os.path.exists(VIRTFILE):
vcmd = mm_cfg.POSTFIX_MAP_CMD + ' ' + VIRTFILE
status = (os.system(vcmd) >> 8) & 0xff
if status:
errstr = os.strerror(status)
- syslog('error', msg, vcmd, status, errstr)
- raise RuntimeError, msg % (vcmd, status, errstr)
+ log.error(msg, vcmd, status, errstr)
+ raise RuntimeError(msg % (vcmd, status, errstr))
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index f1703a50e..a47a94316 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -30,6 +30,7 @@ import shutil
import socket
import urllib
import cPickle
+import logging
import marshal
import email.Iterators
@@ -64,17 +65,21 @@ from Mailman.TopicMgr import TopicMgr
from Mailman import Gui
# Other useful classes
+from Mailman import i18n
from Mailman import MemberAdaptor
from Mailman import Message
from Mailman import Site
-from Mailman import i18n
-from Mailman.Logging.Syslog import syslog
from Mailman.OldStyleMemberships import OldStyleMemberships
_ = i18n._
EMPTYSTRING = ''
+clog = logging.getLogger('mailman.config')
+elog = logging.getLogger('mailman.error')
+vlog = logging.getLogger('mailman.vette')
+slog = logging.getLogger('mailman.subscribe')
+
# Use mixins here just to avoid having any one chunk be too large.
@@ -111,7 +116,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
if e.errno == errno.ENOENT:
pass
else:
- syslog('error', 'IOError reading list extension: %s', e)
+ elog.error('IOError reading list extension: %s', e)
else:
func = dict.get('extend')
if func:
@@ -515,8 +520,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
os.fsync(fp.fileno())
fp.close()
except IOError, e:
- syslog('error',
- 'Failed config.pck write, retaining old state.\n%s', e)
+ elog.error('Failed config.pck write, retaining old state.\n%s', e)
if fp is not None:
os.unlink(fname_tmp)
raise
@@ -624,8 +628,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
if dict is None:
if e is not None:
# Had problems with this file; log it and try the next one.
- syslog('error', "couldn't load config file %s\n%s",
- file, e)
+ elog.error("couldn't load config file %s\n%s", file, e)
else:
# We already have the most up-to-date state
return
@@ -633,15 +636,15 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
break
else:
# Nothing worked, so we have to give up
- syslog('error', 'All %s fallbacks were corrupt, giving up',
- self.internal_name())
+ elog.error('All %s fallbacks were corrupt, giving up',
+ self.internal_name())
raise Errors.MMCorruptListDatabaseError, e
# Now, if we didn't end up using the primary database file, we want to
# copy the fallback into the primary so that the logic in Save() will
# still work. For giggles, we'll copy it to a safety backup. Note we
# MUST do this with the underlying list lock acquired.
if file == plast or file == dlast:
- syslog('error', 'fixing corrupt config file, using: %s', file)
+ elog.error('fixing corrupt config file, using: %s', file)
unlock = True
try:
try:
@@ -733,8 +736,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
if self.reply_to_address.strip() and self.reply_goes_to_list:
Utils.ValidateEmail(self.reply_to_address)
except Errors.EmailAddressError:
- syslog('error', 'Bad reply_to_address "%s" cleared for list: %s',
- self.reply_to_address, self.internal_name())
+ elog.error('Bad reply_to_address "%s" cleared for list: %s',
+ self.reply_to_address, self.internal_name())
self.reply_to_address = ''
self.reply_goes_to_list = 0
# Legacy topics may have bad regular expressions in their patterns
@@ -743,8 +746,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
try:
re.compile(pattern)
except (re.error, TypeError):
- syslog('error', 'Bad topic pattern "%s" for list: %s',
- pattern, self.internal_name())
+ elog.error('Bad topic pattern "%s" for list: %s',
+ pattern, self.internal_name())
else:
goodtopics.append((name, pattern, desc, emptyflag))
self.topics = goodtopics
@@ -842,8 +845,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
# Is the subscribing address banned from this list?
pattern = self.GetBannedPattern(email)
if pattern:
- syslog('vette', '%s banned subscription: %s (matched: %s)',
- realname, email, pattern)
+ vlog.error('%s banned subscription: %s (matched: %s)',
+ realname, email, pattern)
raise Errors.MembershipIsBanned, pattern
# Sanity check the digest flag
if digest and not self.digestable:
@@ -896,8 +899,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
msg['Reply-To'] = self.GetRequestEmail(cookie)
msg.send(self)
who = formataddr((name, email))
- syslog('subscribe', '%s: pending %s %s',
- self.internal_name(), who, by)
+ slog.info('%s: pending %s %s', self.internal_name(), who, by)
raise Errors.MMSubscribeNeedsConfirmation
elif self.HasAutoApprovedSender(email):
# no approval necessary:
@@ -965,8 +967,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
kind = ' (digest)'
else:
kind = ''
- syslog('subscribe', '%s: new%s %s, %s', self.internal_name(),
- kind, formataddr((name, email)), whence)
+ slog.info('%s: new%s %s, %s', self.internal_name(),
+ kind, formataddr((name, email)), whence)
if ack:
self.SendSubscribeAck(email, self.getMemberPassword(email),
digest, text)
@@ -1027,8 +1029,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
whence = "; %s" % whence
else:
whence = ""
- syslog('subscribe', '%s: deleted %s%s',
- self.internal_name(), name, whence)
+ slog.info('%s: deleted %s%s', self.internal_name(), name, whence)
def ChangeMemberName(self, addr, name, globally):
self.setMemberName(addr, name)
@@ -1071,9 +1072,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
# too harsh.
pattern = self.GetBannedPattern(newaddr)
if pattern:
- syslog('vette',
- '%s banned address change: %s -> %s (matched: %s)',
- realname, oldaddr, newaddr, pattern)
+ vlog.error('%s banned address change: %s -> %s (matched: %s)',
+ realname, oldaddr, newaddr, pattern)
raise Errors.MembershipIsBanned, pattern
# Pend the subscription change
cookie = self.pend_new(Pending.CHANGE_OF_ADDRESS,
@@ -1153,8 +1153,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
def log_and_notify_admin(self, oldaddr, newaddr):
"""Log member address change and notify admin if requested."""
- syslog('subscribe', '%s: changed member address from %s to %s',
- self.internal_name(), oldaddr, newaddr)
+ slog.info('%s: changed member address from %s to %s',
+ self.internal_name(), oldaddr, newaddr)
if self.admin_notify_mchanges:
lang = self.preferred_language
otrans = i18n.get_translation()
@@ -1299,7 +1299,7 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
except KeyError:
# Most likely because the message has already been disposed of
# via the admindb page.
- syslog('error', 'Could not process HELD_MESSAGE: %s', id)
+ elog.error('Could not process HELD_MESSAGE: %s', id)
return (op,)
elif op == Pending.RE_ENABLE:
member = data[1]
@@ -1417,8 +1417,8 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
if i < 0:
# This didn't look like a header line. BAW: should do a
# better job of informing the list admin.
- syslog('config', 'bad bounce_matching_header line: %s\n%s',
- self.real_name, line)
+ clog.error('bad bounce_matching_header line: %s\n%s',
+ self.real_name, line)
else:
header = line[:i]
value = line[i+1:].lstrip()
@@ -1427,9 +1427,9 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
except re.error, e:
# The regexp was malformed. BAW: should do a better
# job of informing the list admin.
- syslog('config', '''\
+ clog.error("""\
bad regexp in bounce_matching_header line: %s
-\n%s (cause: %s)''', self.real_name, value, e)
+\n%s (cause: %s)""", self.real_name, value, e)
else:
all.append((header, cre, line))
return all
@@ -1471,12 +1471,10 @@ bad regexp in bounce_matching_header line: %s
date, count = info
if count < 0:
# They've already hit the limit for today.
- syslog('vette', '-request/hold autoresponse discarded for: %s',
- sender)
+ vlog.info('-request/hold autoresponse discarded for: %s', sender)
return 0
if count >= mm_cfg.MAX_AUTORESPONSES_PER_DAY:
- syslog('vette', '-request/hold autoresponse limit hit for: %s',
- sender)
+ vlog.info('-request/hold autoresponse limit hit for: %s', sender)
self.hold_and_cmd_autoresponses[sender] = (today, -1)
# Send this notification message instead
text = Utils.maketext(
@@ -1509,8 +1507,8 @@ bad regexp in bounce_matching_header line: %s
auto_approve = False
if self.GetPattern(sender, self.subscribe_auto_approval):
auto_approve = True
- syslog('vette', '%s: auto approved subscribe from %s',
- self.internal_name(), sender)
+ vlog.info('%s: auto approved subscribe from %s',
+ self.internal_name(), sender)
return auto_approve
def GetPattern(self, email, pattern_list):
diff --git a/Mailman/Queue/BounceRunner.py b/Mailman/Queue/BounceRunner.py
index cb125ef58..0063635ac 100644
--- a/Mailman/Queue/BounceRunner.py
+++ b/Mailman/Queue/BounceRunner.py
@@ -21,23 +21,26 @@ import os
import re
import time
import cPickle
+import logging
from email.MIMEMessage import MIMEMessage
from email.MIMEText import MIMEText
from email.Utils import parseaddr
from Mailman import LockFile
-from Mailman import Utils
from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.Bouncers import BouncerAPI
-from Mailman.Logging.Syslog import syslog
+from Mailman.i18n import _
from Mailman.Message import UserNotification
from Mailman.Queue.Runner import Runner
from Mailman.Queue.sbcache import get_switchboard
-from Mailman.i18n import _
COMMASPACE = ', '
+log = logging.getLogger('mailman.bounce')
+elog = logging.getLogger('mailman.error')
+
class BounceMixin:
@@ -96,8 +99,7 @@ class BounceMixin:
self._bouncecnt += len(addrs)
def _register_bounces(self):
- syslog('bounce', '%s processing %s queued bounces',
- self, self._bouncecnt)
+ log.info('%s processing %s queued bounces', self, self._bouncecnt)
# Read all the records from the bounce file, then unlink it. Sort the
# records by listname for more efficient processing.
events = {}
@@ -106,7 +108,7 @@ class BounceMixin:
try:
listname, addr, day, msg = cPickle.load(self._bounce_events_fp)
except ValueError, e:
- syslog('bounce', 'Error reading bounce events: %s', e)
+ log.error('Error reading bounce events: %s', e)
except EOFError:
break
events.setdefault(listname, []).append((addr, day, msg))
@@ -210,8 +212,8 @@ class BounceRunner(Runner, BounceMixin):
# If that still didn't return us any useful addresses, then send it on
# or discard it.
if not addrs:
- syslog('bounce', 'bounce message w/no discernable addresses: %s',
- msg.get('message-id'))
+ log.info('bounce message w/no discernable addresses: %s',
+ msg.get('message-id'))
maybe_forward(mlist, msg)
return
# BAW: It's possible that there are None's in the list of addresses,
@@ -252,9 +254,8 @@ def verp_bounce(mlist, msg):
# All is good
addr = '%s@%s' % mo.group('mailbox', 'host')
except IndexError:
- syslog('error',
- "VERP_REGEXP doesn't yield the right match groups: %s",
- mm_cfg.VERP_REGEXP)
+ elog.error("VERP_REGEXP doesn't yield the right match groups: %s",
+ mm_cfg.VERP_REGEXP)
return []
return [addr]
@@ -287,8 +288,7 @@ def verp_probe(mlist, msg):
if data is not None:
return token
except IndexError:
- syslog(
- 'error',
+ elog.error(
"VERP_PROBE_REGEXP doesn't yield the right match groups: %s",
mm_cfg.VERP_PROBE_REGEXP)
return None
@@ -313,8 +313,8 @@ For more information see:
"""),
subject=_('Uncaught bounce notification'),
tomoderators=0)
- syslog('bounce', 'forwarding unrecognized, message-id: %s',
- msg.get('message-id', 'n/a'))
+ log.error('forwarding unrecognized, message-id: %s',
+ msg.get('message-id', 'n/a'))
else:
- syslog('bounce', 'discarding unrecognized, message-id: %s',
- msg.get('message-id', 'n/a'))
+ log.error('discarding unrecognized, message-id: %s',
+ msg.get('message-id', 'n/a'))
diff --git a/Mailman/Queue/CommandRunner.py b/Mailman/Queue/CommandRunner.py
index 64b8f0758..978cb05cd 100644
--- a/Mailman/Queue/CommandRunner.py
+++ b/Mailman/Queue/CommandRunner.py
@@ -21,10 +21,9 @@
# bounce messages (i.e. -admin or -bounces), nor does it handle mail to
# -owner.
-
-
import re
import sys
+import logging
from email.Errors import HeaderParseError
from email.Header import decode_header, make_header, Header
@@ -35,15 +34,16 @@ from types import StringType, UnicodeType
from Mailman import LockFile
from Mailman import Message
-from Mailman import Utils
from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.Handlers import Replybot
-from Mailman.Logging.Syslog import syslog
-from Mailman.Queue.Runner import Runner
from Mailman.i18n import _
+from Mailman.Queue.Runner import Runner
NL = '\n'
+log = logging.getLogger('mailman.vette')
+
class Results:
@@ -202,14 +202,14 @@ class CommandRunner(Runner):
precedence = msg.get('precedence', '').lower()
ack = msg.get('x-ack', '').lower()
if ack <> 'yes' and precedence in ('bulk', 'junk', 'list'):
- syslog('vette', 'Precedence: %s message discarded by: %s',
- precedence, mlist.GetRequestEmail())
+ log.info('Precedence: %s message discarded by: %s',
+ precedence, mlist.GetRequestEmail())
return False
# Do replybot for commands
mlist.Load()
Replybot.process(mlist, msg, msgdata)
if mlist.autorespond_requests == 1:
- syslog('vette', 'replied and discard')
+ log.info('replied and discard')
# w/discard
return False
# Now craft the response
diff --git a/Mailman/Queue/IncomingRunner.py b/Mailman/Queue/IncomingRunner.py
index 71d939197..19a315040 100644
--- a/Mailman/Queue/IncomingRunner.py
+++ b/Mailman/Queue/IncomingRunner.py
@@ -1,4 +1,4 @@
-# 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
@@ -93,16 +93,21 @@
# performed. Results notifications are sent to the author of the message,
# which all bounces pointing back to the -bounces address.
+
-import sys
import os
+import sys
+import logging
+
from cStringIO import StringIO
-from Mailman import mm_cfg
from Mailman import Errors
from Mailman import LockFile
+from Mailman import mm_cfg
from Mailman.Queue.Runner import Runner
-from Mailman.Logging.Syslog import syslog
+
+log = logging.getLogger('mailman.error')
+vlog = logging.getLogger('mailman.vette')
@@ -153,12 +158,12 @@ class IncomingRunner(Runner):
sys.modules[modname].process(mlist, msg, msgdata)
# Failsafe -- a child may have leaked through.
if pid <> os.getpid():
- syslog('error', 'child process leaked thru: %s', modname)
+ log.error('child process leaked thru: %s', modname)
os._exit(1)
except Errors.DiscardMessage:
# Throw the message away; we need do nothing else with it.
- syslog('vette', 'Message discarded, msgid: %s',
- msg.get('message-id', 'n/a'))
+ vlog.info('Message discarded, msgid: %s',
+ msg.get('message-id', 'n/a'))
return 0
except Errors.HoldMessage:
# Let the approval process take it from here. The message no
diff --git a/Mailman/Queue/MaildirRunner.py b/Mailman/Queue/MaildirRunner.py
index 39971ae2a..97b71c7ef 100644
--- a/Mailman/Queue/MaildirRunner.py
+++ b/Mailman/Queue/MaildirRunner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2002 by the Free Software Foundation, Inc.
+# Copyright (C) 2002-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
@@ -12,7 +12,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.
"""Maildir pre-queue runner.
@@ -51,6 +52,7 @@ mechanism.
import os
import re
import errno
+import logging
from email.Parser import Parser
from email.Utils import parseaddr
@@ -60,7 +62,6 @@ from Mailman import Utils
from Mailman.Message import Message
from Mailman.Queue.Runner import Runner
from Mailman.Queue.sbcache import get_switchboard
-from Mailman.Logging.Syslog import syslog
# We only care about the listname and the subq as in listname@ or
# listname-request@
@@ -73,6 +74,8 @@ lre = re.compile(r"""
)? # if it exists
""", re.VERBOSE | re.IGNORECASE)
+log = logging.getLogger('mailman.error')
+
class MaildirRunner(Runner):
@@ -110,7 +113,7 @@ class MaildirRunner(Runner):
if e.errno == errno.ENOENT:
# Some other MaildirRunner beat us to it
continue
- syslog('error', 'Could not rename maildir file: %s', srcname)
+ log.error('Could not rename maildir file: %s', srcname)
raise
# Now open, read, parse, and enqueue this message
try:
@@ -139,8 +142,8 @@ class MaildirRunner(Runner):
else:
# As far as we can tell, this message isn't destined for
# any list on the system. What to do?
- syslog('error', 'Message apparently not for any list: %s',
- xdstname)
+ log.error('Message apparently not for any list: %s',
+ xdstname)
os.rename(dstname, xdstname)
continue
# BAW: blech, hardcoded
@@ -171,14 +174,14 @@ class MaildirRunner(Runner):
msgdata['torequest'] = 1
queue = get_switchboard(mm_cfg.CMDQUEUE_DIR)
else:
- syslog('error', 'Unknown sub-queue: %s', subq)
+ log.error('Unknown sub-queue: %s', subq)
os.rename(dstname, xdstname)
continue
queue.enqueue(msg, msgdata)
os.unlink(dstname)
except Exception, e:
os.rename(dstname, xdstname)
- syslog('error', str(e))
+ log.error('%s', e)
def _cleanup(self):
pass
diff --git a/Mailman/Queue/NewsRunner.py b/Mailman/Queue/NewsRunner.py
index fa0e91377..7a71f5bf2 100644
--- a/Mailman/Queue/NewsRunner.py
+++ b/Mailman/Queue/NewsRunner.py
@@ -19,6 +19,7 @@
import re
import email
import socket
+import logging
import nntplib
from cStringIO import StringIO
@@ -26,11 +27,11 @@ from email.Utils import getaddresses
COMMASPACE = ', '
-from Mailman import Utils
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
from Mailman.Queue.Runner import Runner
+log = logging.getLogger('mailman.error')
# Matches our Mailman crafted Message-IDs. See Utils.unique_message_id()
mcre = re.compile(r"""
@@ -67,13 +68,11 @@ class NewsRunner(Runner):
password=mm_cfg.NNTP_PASSWORD)
conn.post(fp)
except nntplib.error_temp, e:
- syslog('error',
- '(NNTPDirect) NNTP error for list "%s": %s',
- mlist.internal_name(), e)
+ log.error('(NNTPDirect) NNTP error for list "%s": %s',
+ mlist.internal_name(), e)
except socket.error, e:
- syslog('error',
- '(NNTPDirect) socket error for list "%s": %s',
- mlist.internal_name(), e)
+ log.error('(NNTPDirect) socket error for list "%s": %s',
+ mlist.internal_name(), e)
finally:
if conn:
conn.quit()
diff --git a/Mailman/Queue/OutgoingRunner.py b/Mailman/Queue/OutgoingRunner.py
index a4a83000a..3d4575ed2 100644
--- a/Mailman/Queue/OutgoingRunner.py
+++ b/Mailman/Queue/OutgoingRunner.py
@@ -22,12 +22,12 @@ import copy
import time
import email
import socket
+import logging
from Mailman import Errors
from Mailman import LockFile
from Mailman import Message
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
from Mailman.Queue.BounceRunner import BounceMixin
from Mailman.Queue.Runner import Runner
from Mailman.Queue.Switchboard import Switchboard
@@ -36,6 +36,8 @@ from Mailman.Queue.Switchboard import Switchboard
# permanent failures. It is a count of calls to _doperiodic()
DEAL_WITH_PERMFAILURES_EVERY = 10
+log = logging.getLogger('mailman.error')
+
class OutgoingRunner(Runner, BounceMixin):
@@ -66,7 +68,7 @@ class OutgoingRunner(Runner, BounceMixin):
self._func(mlist, msg, msgdata)
# Failsafe -- a child may have leaked through.
if pid <> os.getpid():
- syslog('error', 'child process leaked thru: %s', modname)
+ log.error('child process leaked thru: %s', modname)
os._exit(1)
self.__logged = False
except socket.error:
@@ -78,8 +80,8 @@ class OutgoingRunner(Runner, BounceMixin):
port = 'smtp'
# Log this just once.
if not self.__logged:
- syslog('error', 'Cannot connect to SMTP server %s on port %s',
- mm_cfg.SMTPHOST, port)
+ log.error('Cannot connect to SMTP server %s on port %s',
+ mm_cfg.SMTPHOST, port)
self.__logged = True
return True
except Errors.SomeRecipientsFailed, e:
diff --git a/Mailman/Queue/Runner.py b/Mailman/Queue/Runner.py
index 7c99c50a5..56baf431b 100644
--- a/Mailman/Queue/Runner.py
+++ b/Mailman/Queue/Runner.py
@@ -19,18 +19,20 @@
import time
import weakref
import traceback
+import logging
import email.Errors
from cStringIO import StringIO
from Mailman import Errors
-from Mailman import MailList
-from Mailman import Utils
from Mailman import i18n
+from Mailman import MailList
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
from Mailman.Queue.Switchboard import Switchboard
+log = logging.getLogger('mailman.error')
+
class Runner:
@@ -97,7 +99,7 @@ class Runner:
# There's not much we can do (and we didn't even get the
# metadata, so just log the exception and continue.
self._log(e)
- syslog('error', 'Ignoring unparseable message: %s', filebase)
+ log.error('Ignoring unparseable message: %s', filebase)
continue
try:
self._onefile(msg, msgdata)
@@ -112,7 +114,7 @@ class Runner:
# Put a marker in the metadata for unshunting
msgdata['whichq'] = self._switchboard.whichq()
filebase = self._shunt.enqueue(msg, msgdata)
- syslog('error', 'SHUNTING: %s', filebase)
+ log.error('SHUNTING: %s', filebase)
# Other work we want to do each time through the loop
Utils.reap(self._kids, once=True)
self._doperiodic()
@@ -133,9 +135,8 @@ class Runner:
listname = mm_cfg.MAILMAN_SITE_LIST
mlist = self._open_list(listname)
if not mlist:
- syslog('error',
- 'Dequeuing message destined for missing list: %s',
- listname)
+ log.error('Dequeuing message destined for missing list: %s',
+ listname)
self._shunt.enqueue(msg, msgdata)
return
# Now process this message, keeping track of any subprocesses that may
@@ -178,17 +179,17 @@ class Runner:
try:
mlist = MailList.MailList(listname, lock=False)
except Errors.MMListError, e:
- syslog('error', 'error opening list: %s\n%s', listname, e)
+ log.error('error opening list: %s\n%s', listname, e)
return None
else:
self._listcache[listname] = mlist
return mlist
def _log(self, exc):
- syslog('error', 'Uncaught runner exception: %s', exc)
+ log.error('Uncaught runner exception: %s', exc)
s = StringIO()
traceback.print_exc(file=s)
- syslog('error', s.getvalue())
+ log.error('%s', s.getvalue())
#
# Subclasses can override these methods.
diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py
index 33177ba8b..36b69283e 100644
--- a/Mailman/Queue/Switchboard.py
+++ b/Mailman/Queue/Switchboard.py
@@ -41,9 +41,8 @@ import cPickle
import marshal
from Mailman import Message
-from Mailman import Utils
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
# 20 bytes of all bits set, maximum sha.digest() value
shamax = 0xffffffffffffffffffffffffffffffffffffffffL
diff --git a/Mailman/SafeDict.py b/Mailman/SafeDict.py
index 12cf03f57..92f6b238e 100644
--- a/Mailman/SafeDict.py
+++ b/Mailman/SafeDict.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998,1999,2000,2001,2002 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
@@ -12,27 +12,25 @@
#
# 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.
"""A `safe' dictionary for string interpolation."""
-from types import StringType
-from UserDict import UserDict
-
COMMASPACE = ', '
-class SafeDict(UserDict):
+class SafeDict(dict):
"""Dictionary which returns a default value for unknown keys.
This is used in maketext so that editing templates is a bit more robust.
"""
def __getitem__(self, key):
try:
- return self.data[key]
+ return super(SafeDict, self).__getitem__(key)
except KeyError:
- if isinstance(key, StringType):
+ if isinstance(key, basestring):
return '%('+key+')s'
else:
return '<Missing key: %s>' % `key`
@@ -43,9 +41,11 @@ class SafeDict(UserDict):
class MsgSafeDict(SafeDict):
- def __init__(self, msg, dict=None):
+ def __init__(self, msg, d=None):
self.__msg = msg
- SafeDict.__init__(self, dict)
+ if d is None:
+ d = {}
+ super(MsgSafeDict, self).__init__(d)
def __getitem__(self, key):
if key.startswith('msg_'):
@@ -57,10 +57,10 @@ class MsgSafeDict(SafeDict):
return 'n/a'
return COMMASPACE.join(all)
else:
- return SafeDict.__getitem__(self, key)
+ return super(MsgSafeDict, self).__getitem__(key)
def copy(self):
- d = self.data.copy()
+ d = super(MsgSafeDict, self).copy()
for k in self.__msg.keys():
vals = self.__msg.get_all(k)
if len(vals) == 1:
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py
index 204daf417..91ab6f52f 100644
--- a/Mailman/SecurityManager.py
+++ b/Mailman/SecurityManager.py
@@ -12,8 +12,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.
"""Handle passwords and sanitize approved messages."""
@@ -53,6 +53,7 @@ import sha
import time
import urllib
import Cookie
+import logging
import marshal
import binascii
@@ -60,15 +61,16 @@ from types import StringType, TupleType
from urlparse import urlparse
from Mailman import Errors
-from Mailman import Utils
from Mailman import mm_cfg
-from Mailman.Logging.Syslog import syslog
+from Mailman import Utils
try:
import crypt
except ImportError:
crypt = None
+log = logging.getLogger('mailman.error')
+
class SecurityManager:
@@ -201,8 +203,8 @@ class SecurityManager:
pass
else:
# What is this context???
- syslog('error', 'Bad authcontext: %s', ac)
- raise ValueError, 'Bad authcontext: %s' % ac
+ log.error('Bad authcontext: %s', ac)
+ raise ValueError('Bad authcontext: %s' % ac)
return mm_cfg.UnAuthorized
def WebAuthenticate(self, authcontexts, response, user=None):
diff --git a/Mailman/Utils.py b/Mailman/Utils.py
index b5b13252d..cb3444b17 100644
--- a/Mailman/Utils.py
+++ b/Mailman/Utils.py
@@ -31,6 +31,7 @@ import time
import errno
import base64
import random
+import logging
import urlparse
import htmlentitydefs
import email.Header
@@ -57,6 +58,8 @@ cre = re.compile(r'%\(([_a-z]\w*?)\)s?', re.IGNORECASE)
# Search for $$, $identifier, or ${identifier}
dre = re.compile(r'(\${2})|\$([_a-z]\w*)|\${([_a-z]\w*)}', re.IGNORECASE)
+log = logging.getLogger('mailman.error')
+
def list_exists(listname):
@@ -311,9 +314,7 @@ def Secure_MakeRandomPassword(length):
# We have no available source of cryptographically
# secure random characters. Log an error and fallback
# to the user friendly passwords.
- from Mailman.Logging.Syslog import syslog
- syslog('error',
- 'urandom not available, passwords not secure')
+ log.error('urandom not available, passwords not secure')
return UserFriendly_MakeRandomPassword(length)
newbytes = os.read(fd, length - bytesread)
bytes.append(newbytes)
@@ -526,8 +527,7 @@ def findtext(templatefile, dict=None, raw=False, lang=None, mlist=None):
text = sdict.interpolate(utemplate)
except (TypeError, ValueError), e:
# The template is really screwed up
- from Mailman.Logging.Syslog import syslog
- syslog('error', 'broken template: %s\n%s', filename, e)
+ log.error('broken template: %s\n%s', filename, e)
pass
if raw:
return text, filename
diff --git a/Mailman/loginit.py b/Mailman/loginit.py
new file mode 100644
index 000000000..323bd2985
--- /dev/null
+++ b/Mailman/loginit.py
@@ -0,0 +1,88 @@
+# Copyright (C) 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
+# 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 logging
+import logging.handlers
+
+from Mailman import mm_cfg
+
+FMT = '%(asctime)s (%(process)d) %(message)s'
+DATEFMT = '%b %d %H:%M:%S %Y'
+LOGGERS = ('bounce', 'mischief', 'post', 'vette', 'smtp',
+ 'smtp-failure', 'subscribe', 'config', 'error',
+ 'qrunner',
+ )
+
+_handlers = []
+
+
+
+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:
+ #
+ # 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
+ #
+ # There was also a 'debug' logger, but that was mostly unused, so instead
+ # we'll use debug level on existing loggers.
+ #
+ # 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)
+ # Create the subloggers
+ for logger in LOGGERS:
+ log = logging.getLogger('mailman.' + logger)
+ # 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)
+ _handlers.append(handler)
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+
+
+
+def reopen():
+ for handler in _handlers:
+ meth = getattr(handler, 'doRollover', None)
+ if meth:
+ meth()
diff --git a/Mailman/versions.py b/Mailman/versions.py
index f050c5b98..4b3990684 100644
--- a/Mailman/versions.py
+++ b/Mailman/versions.py
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2005 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
@@ -32,14 +32,16 @@ number of the list, and then does a .Save(), so the transformations won't be
run again until another version change is detected.
"""
+import logging
from types import ListType, StringType
from Mailman import mm_cfg
-from Mailman import Utils
from Mailman import Message
+from Mailman import Utils
from Mailman.MemberAdaptor import UNKNOWN
-from Mailman.Logging.Syslog import syslog
+
+log = logging.getLogger('mailman.error')
@@ -172,7 +174,6 @@ def UpdateOldVars(l, stored_state):
if hasattr(l, 'moderated'):
# We'll assume we're converting all these attributes at once
if l.moderated:
- #syslog('debug', 'Case 1')
for addr in l.posters:
if not l.isMember(addr):
l.accept_these_nonmembers.append(addr)
@@ -183,7 +184,6 @@ def UpdateOldVars(l, stored_state):
l.generic_nonmember_action = 1
l.default_member_moderation = 1
elif l.member_posting_only:
- #syslog('debug', 'Case 2')
for addr in l.posters:
if not l.isMember(addr):
l.accept_these_nonmembers.append(addr)
@@ -192,13 +192,11 @@ def UpdateOldVars(l, stored_state):
l.generic_nonmember_action = 1
l.default_member_moderation = 0
elif not l.posters:
- #syslog('debug', 'Case 3')
for member in l.getMembers():
l.setMemberOption(member, mm_cfg.Moderate, 0)
l.generic_nonmember_action = 0
l.default_member_moderation = 0
else:
- #syslog('debug', 'Case 4')
for addr in l.posters:
if not l.isMember(addr):
l.accept_these_nonmembers.append(addr)
@@ -506,6 +504,6 @@ def NewRequestsDatabase(l):
mm_cfg.DEFAULT_SERVER_LANGUAGE)
del r[k]
else:
- syslog('error', """\
+ log.error("""\
VERY BAD NEWS. Unknown pending request type `%s' found for list: %s""",
k, l.internal_name())
diff --git a/Makefile.in b/Makefile.in
index fac0321e7..0328d0c2d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -49,7 +49,7 @@ VAR_DIRS= \
ARCH_INDEP_DIRS= \
bin templates scripts cron pythonlib \
- Mailman Mailman/Cgi Mailman/Logging Mailman/Archiver \
+ Mailman Mailman/Cgi Mailman/Archiver \
Mailman/Handlers Mailman/Queue Mailman/Bouncers \
Mailman/MTA Mailman/Gui Mailman/Commands messages icons \
tests tests/bounces tests/msgs
diff --git a/bin/qrunner b/bin/qrunner
index 20fe830d1..c076b00cd 100644
--- a/bin/qrunner
+++ b/bin/qrunner
@@ -75,11 +75,12 @@ operation. It is only useful for debugging if it is run separately.
import sys
import getopt
import signal
+import logging
import paths
from Mailman import mm_cfg
+from Mailman import loginit
from Mailman.i18n import _
-from Mailman.Logging.Syslog import syslog
from Mailman.Logging.Utils import LogStdErr
PROGRAM = sys.argv[0]
@@ -88,6 +89,8 @@ COMMASPACE = ', '
# Flag which says whether we're running under mailmanctl or not.
AS_SUBPROC = 0
+log = logging.getLogger('mailman.qrunner')
+
def usage(code, msg=''):
@@ -133,7 +136,7 @@ def set_signals(loop):
# Exit the qrunner cleanly
loop.stop()
loop.status = signal.SIGTERM
- syslog('qrunner', '%s qrunner caught SIGTERM. Stopping.', loop.name())
+ log.info('%s qrunner caught SIGTERM. Stopping.', loop.name())
signal.signal(signal.SIGTERM, sigterm_handler)
# Set up the SIGINT handler for stopping the loop. For us, SIGINT is
# the same as SIGTERM, but our parent treats the exit statuses
@@ -142,14 +145,12 @@ def set_signals(loop):
# Exit the qrunner cleanly
loop.stop()
loop.status = signal.SIGINT
- syslog('qrunner', '%s qrunner caught SIGINT. Stopping.', loop.name())
+ log.info('%s qrunner caught SIGINT. Stopping.', loop.name())
signal.signal(signal.SIGINT, sigint_handler)
- # SIGHUP just tells us to close our log files. They'll be
- # automatically reopened at the next log print :)
+ # SIGHUP just tells us to rotate our log files.
def sighup_handler(signum, frame, loop=loop):
- syslog.close()
- syslog('qrunner', '%s qrunner caught SIGHUP. Reopening logs.',
- loop.name())
+ loginit.reopen()
+ log.info('%s qrunner caught SIGHUP. Reopening logs.', loop.name())
signal.signal(signal.SIGHUP, sighup_handler)
@@ -214,11 +215,11 @@ def main():
if len(runners) == 0:
usage(1, _('No runner name given.'))
- # Before we startup qrunners, we redirect the stderr to mailman syslog.
- # We assume !AS_SUBPROC is running for debugging purpose and don't
- # log errors in mailman logs/error but keep printing to stderr.
- if AS_SUBPROC:
- LogStdErr('error', 'qrunner', manual_reprime=0, tee_to_real_stderr=0)
+ # If we're not running as a subprocess of mailmanctl, then we'll log to
+ # 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)
# Fast track for one infinite runner
if len(runners) == 1 and not once:
@@ -234,9 +235,9 @@ def main():
loop = Loop(qrunner)
set_signals(loop)
# Now start up the main loop
- syslog('qrunner', '%s qrunner started.', loop.name())
+ log.info('%s qrunner started.', loop.name())
qrunner.run()
- syslog('qrunner', '%s qrunner exiting.', loop.name())
+ log.info('%s qrunner exiting.', loop.name())
else:
# Anything else we have to handle a bit more specially
qrunners = []
@@ -256,19 +257,19 @@ def main():
return self.__isdone
loop = Loop()
set_signals(loop)
- syslog('qrunner', 'Main qrunner loop started.')
+ log.info('Main qrunner loop started.')
while not loop.isdone():
for qrunner in qrunners:
# In case the SIGTERM came in the middle of this iteration
if loop.isdone():
break
if verbose:
- syslog('qrunner', 'Now doing a %s qrunner iteration',
- qrunner.__class__.__bases__[0].__name__)
+ log.info('Now doing a %s qrunner iteration',
+ qrunner.__class__.__bases__[0].__name__)
qrunner.run()
if once:
break
- syslog('qrunner', 'Main qrunner loop exiting.')
+ log.info('Main qrunner loop exiting.')
# All done
sys.exit(loop.status)
diff --git a/configure b/configure
index ccdc6599e..f0ef9f2f7 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.in Revision: 2.45 .
+# From configure.in Revision: 7627 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
@@ -4322,7 +4322,7 @@ build/cron/senddigests:cron/senddigests \
# scripts. They're removed on a make distclean, so we make them here.
mkdir -p build/bin build/contrib build/cron
- ac_config_files="$ac_config_files misc/paths.py Mailman/Defaults.py Mailman/mm_cfg.py.dist src/Makefile misc/Makefile bin/Makefile Mailman/Makefile Mailman/Cgi/Makefile Mailman/Logging/Makefile Mailman/Archiver/Makefile Mailman/Commands/Makefile Mailman/Handlers/Makefile Mailman/Bouncers/Makefile Mailman/Queue/Makefile Mailman/MTA/Makefile Mailman/Gui/Makefile templates/Makefile cron/Makefile scripts/Makefile messages/Makefile cron/crontab.in misc/mailman Makefile tests/Makefile tests/bounces/Makefile tests/msgs/Makefile $SCRIPTS"
+ ac_config_files="$ac_config_files misc/paths.py Mailman/Defaults.py Mailman/mm_cfg.py.dist src/Makefile misc/Makefile bin/Makefile Mailman/Makefile Mailman/Cgi/Makefile Mailman/Archiver/Makefile Mailman/Commands/Makefile Mailman/Handlers/Makefile Mailman/Bouncers/Makefile Mailman/Queue/Makefile Mailman/MTA/Makefile Mailman/Gui/Makefile templates/Makefile cron/Makefile scripts/Makefile messages/Makefile cron/crontab.in misc/mailman Makefile tests/Makefile tests/bounces/Makefile tests/msgs/Makefile $SCRIPTS"
ac_config_commands="$ac_config_commands default"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -4886,7 +4886,6 @@ do
"bin/Makefile" ) CONFIG_FILES="$CONFIG_FILES bin/Makefile" ;;
"Mailman/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Makefile" ;;
"Mailman/Cgi/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Cgi/Makefile" ;;
- "Mailman/Logging/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Logging/Makefile" ;;
"Mailman/Archiver/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Archiver/Makefile" ;;
"Mailman/Commands/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Commands/Makefile" ;;
"Mailman/Handlers/Makefile" ) CONFIG_FILES="$CONFIG_FILES Mailman/Handlers/Makefile" ;;
diff --git a/configure.in b/configure.in
index bb57b83e1..dd3d9a547 100644
--- a/configure.in
+++ b/configure.in
@@ -1,4 +1,4 @@
-# Copyright (C) 1998-2004 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
@@ -15,7 +15,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
dnl Process this file with autoconf to produce a configure script.
-AC_REVISION($Revision: 7627 $)
+AC_REVISION($Revision: 7858 $)
AC_PREREQ(2.0)
AC_INIT(src/common.h)
@@ -666,7 +666,7 @@ mkdir -p build/bin build/contrib build/cron
dnl Output everything
AC_OUTPUT([misc/paths.py Mailman/Defaults.py Mailman/mm_cfg.py.dist
src/Makefile misc/Makefile bin/Makefile
- Mailman/Makefile Mailman/Cgi/Makefile Mailman/Logging/Makefile
+ Mailman/Makefile Mailman/Cgi/Makefile
Mailman/Archiver/Makefile Mailman/Commands/Makefile
Mailman/Handlers/Makefile Mailman/Bouncers/Makefile
Mailman/Queue/Makefile Mailman/MTA/Makefile Mailman/Gui/Makefile
diff --git a/scripts/driver b/scripts/driver
index ea43c40eb..08bee07bd 100644
--- a/scripts/driver
+++ b/scripts/driver
@@ -1,6 +1,6 @@
# -*- python -*-
-# Copyright (C) 1998-2004 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.
# This better succeed. If this fails, Python is royally screwed so we might
# as well let the Web server give us a fatal and obtrusive error.
@@ -25,15 +26,17 @@ import sys
# The driver script prints out a lot of information when a Mailman bug is
# encountered. This really helps for development, but it also reveals
# information about the host system that some administrators are not
-# comfortable with. By setting STEALTH_MODE to 1, you disable the printing of
-# this information to the web pages. This information is still, and always,
-# printed in the error logs.
-STEALTH_MODE = 1
+# comfortable with. By setting STEALTH_MODE to True, you disable the printing
+# of this information to the web pages. This information is still, and
+# always, printed in the error logs.
+STEALTH_MODE = True
# This will be set to the entity escaper.
def websafe(s):
return s
+SPACE = ' '
+
# This standard driver script is used to run CGI programs, wrapped in code
@@ -62,7 +65,7 @@ def run_main():
# These will ensure that even if something between now and the
# creation of the real logger below fails, we can still get
# *something* meaningful.
- logger = None
+ log = None
try:
import paths
# When running in non-stealth mode, we need to escape entities,
@@ -71,19 +74,18 @@ def run_main():
if not STEALTH_MODE:
from Mailman.Utils import websafe
except:
- STEALTH_MODE = 1
+ STEALTH_MODE = True
raise
- # Map stderr to a logger, if possible.
- from Mailman.Logging.StampedLogger import StampedLogger
- logger = StampedLogger('error',
- label='admin',
- manual_reprime=1,
- nofail=0,
- immediate=1)
- # Collect stdout in a cStringIO so that if /any/ errors occur during
- # printing it won't mess up our diagnostics page.
+ # Initialize the standard loggers
+ from Mailman.loginit import initialize
+ initialize()
+ import logging
+ log = logging.getLogger('mailman.error')
+ # Collect stdout and stderr in cStringIOs so that if /any/ errors
+ # occur during printing it won't mess up our diagnostics page.
from cStringIO import StringIO
tempstdout = StringIO()
+ tempstderr = StringIO()
# The name of the module to run is passed in argv[1]. What we
# actually do is import the module named by argv[1] that lives in the
# Mailman.Cgi package. That module must have a main() function, which
@@ -96,10 +98,11 @@ def run_main():
main = getattr(module, 'main')
try:
try:
- sys.stderr = logger
sys.stdout = tempstdout
+ sys.stderr = tempstderr
main()
sys.__stdout__.write(tempstdout.getvalue())
+ sys.__stderr__.write(tempstderr.getvalue())
finally:
sys.stderr = sys.__stderr__
sys.stdout = sys.__stdout__
@@ -108,19 +111,15 @@ def run_main():
# produced is still written out to the browser.
sys.stdout.write(tempstdout.getvalue())
except:
- print_traceback(logger)
- print_environment(logger)
+ print_traceback(log)
+ print_environment(log)
-# We are printing error reporting to two places. One will always be stdout
-# and the other will always be the log file. It is assumed that stdout is an
-# HTML sink and the log file is a plain text sink.
-
-def print_traceback(logfp=None):
- if logfp is None:
- logfp = sys.__stderr__
-
+# If possible, we print the error to two places. One will always be stdout
+# and the other will be the log file if a log file was created. It is assumed
+# that stdout is an HTML sink.
+def print_traceback(log=None):
try:
import traceback
except ImportError:
@@ -131,14 +130,22 @@ def print_traceback(logfp=None):
VERSION = '&lt;undetermined&gt;'
# Write to the log file first.
- print >> logfp, '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
- print >> logfp, '[----- Mailman Version: %s -----]' % VERSION
- print >> logfp, '[----- Traceback ------]'
- if traceback:
- traceback.print_exc(file=logfp)
- else:
- print >> logfp, '[failed to import module traceback]'
- print >> logfp, '[exc: %s, var: %s]' % sys.exc_info()[0:2]
+ if log:
+ from cStringIO import StringIO
+ outfp = StringIO()
+
+ print >> outfp, '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
+ print >> outfp, '[----- Mailman Version: %s -----]' % VERSION
+ print >> outfp, '[----- Traceback ------]'
+ if traceback:
+ traceback.print_exc(file=outfp)
+ else:
+ print >> outfp, '[failed to import module traceback]'
+ print >> outfp, '[exc: %s, var: %s]' % sys.exc_info()[0:2]
+ # Don't use .exception() since that'll give us the exception twice.
+ # IWBNI we could print directly to the log's stream, or treat a log
+ # like an output stream.
+ log.error('%s', outfp.getvalue())
# Write to the HTML sink.
print """\
@@ -170,23 +177,24 @@ Mailman error logs.'''
-def print_environment(logfp=None):
- if logfp is None:
- logfp = sys.__stderr__
-
+def print_environment(log=None):
try:
import os
except ImportError:
os = None
- # Write some information about our Python executable to the log file.
- print >> logfp, '[----- Python Information -----]'
- print >> logfp, 'sys.version =', sys.version
- print >> logfp, 'sys.executable =', sys.executable
- print >> logfp, 'sys.prefix =', sys.prefix
- print >> logfp, 'sys.exec_prefix =', sys.exec_prefix
- print >> logfp, 'sys.path =', sys.exec_prefix
- print >> logfp, 'sys.platform =', sys.platform
+ if log:
+ from cStringIO import StringIO
+ outfp = StringIO()
+
+ # Write some information about our Python executable to the log file.
+ print >> outfp, '[----- Python Information -----]'
+ print >> outfp, 'sys.version =', sys.version
+ print >> outfp, 'sys.executable =', sys.executable
+ print >> outfp, 'sys.prefix =', sys.prefix
+ print >> outfp, 'sys.exec_prefix =', sys.exec_prefix
+ print >> outfp, 'sys.path =', sys.exec_prefix
+ print >> outfp, 'sys.platform =', sys.platform
# Write the same information to the HTML sink.
if not STEALTH_MODE:
@@ -211,12 +219,13 @@ def print_environment(logfp=None):
print '</table>'
# Write environment variables to the log file.
- print >> logfp, '[----- Environment Variables -----]'
- if os:
- for k, v in os.environ.items():
- print >> logfp, '\t%s: %s' % (k, v)
- else:
- print >> logfp, '[failed to import module os]'
+ if log:
+ print >> logfp, '[----- Environment Variables -----]'
+ if os:
+ for k, v in os.environ.items():
+ print >> outfp, '\t%s: %s' % (k, v)
+ else:
+ print >> outfp, '[failed to import module os]'
# Write environment variables to the HTML sink.
if not STEALTH_MODE:
@@ -235,6 +244,10 @@ def print_environment(logfp=None):
else:
print '<p><hr>[failed to import module os]'
+ # Dump the log output
+ if log:
+ log.error('%s', outfp.getvalue())
+
try: