Issue #7086: Added TCP support to SysLogHandler and tidied up some anachronisms in the code.

This commit is contained in:
Vinay Sajip 2009-10-10 20:32:36 +00:00
parent 6e3dbbdf39
commit 1c77b7f84c
5 changed files with 90 additions and 77 deletions

View File

@ -764,12 +764,12 @@ functions.
Does basic configuration for the logging system by creating a Does basic configuration for the logging system by creating a
:class:`StreamHandler` with a default :class:`Formatter` and adding it to the :class:`StreamHandler` with a default :class:`Formatter` and adding it to the
root logger. The function does nothing if any handlers have been defined for root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
the root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
:func:`error` and :func:`critical` will call :func:`basicConfig` automatically :func:`error` and :func:`critical` will call :func:`basicConfig` automatically
if no handlers are defined for the root logger. if no handlers are defined for the root logger.
This function does nothing if the root logger already has handlers configured. This function does nothing if the root logger already has handlers
configured for it.
.. versionchanged:: 2.4 .. versionchanged:: 2.4
Formerly, :func:`basicConfig` did not take any keyword arguments. Formerly, :func:`basicConfig` did not take any keyword arguments.
@ -2008,16 +2008,22 @@ The :class:`SysLogHandler` class, located in the :mod:`logging.handlers` module,
supports sending logging messages to a remote or local Unix syslog. supports sending logging messages to a remote or local Unix syslog.
.. class:: SysLogHandler([address[, facility]]) .. class:: SysLogHandler([address[, facility[, socktype]]])
Returns a new instance of the :class:`SysLogHandler` class intended to Returns a new instance of the :class:`SysLogHandler` class intended to
communicate with a remote Unix machine whose address is given by *address* in communicate with a remote Unix machine whose address is given by *address* in
the form of a ``(host, port)`` tuple. If *address* is not specified, the form of a ``(host, port)`` tuple. If *address* is not specified,
``('localhost', 514)`` is used. The address is used to open a UDP socket. An ``('localhost', 514)`` is used. The address is used to open a socket. An
alternative to providing a ``(host, port)`` tuple is providing an address as a alternative to providing a ``(host, port)`` tuple is providing an address as a
string, for example "/dev/log". In this case, a Unix domain socket is used to string, for example "/dev/log". In this case, a Unix domain socket is used to
send the message to the syslog. If *facility* is not specified, send the message to the syslog. If *facility* is not specified,
:const:`LOG_USER` is used. :const:`LOG_USER` is used. The type of socket opened depends on the
*socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus
opens a UDP socket. To open a TCP socket (for use with the newer syslog
daemons such as rsyslog), specify a value of :const:`socket.SOCK_STREAM`.
.. versionchanged:: 2.7
*socktype* was added.
.. method:: close() .. method:: close()

View File

@ -23,6 +23,8 @@ Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging' and log away! To use, simply 'import logging' and log away!
""" """
import sys, os, time, cStringIO, traceback, warnings
__all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO', 'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO',
'LogRecord', 'Logger', 'LoggerAdapter', 'NOTSET', 'NullHandler', 'LogRecord', 'Logger', 'LoggerAdapter', 'NOTSET', 'NullHandler',
@ -31,8 +33,6 @@ __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass',
'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning'] 'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning']
import sys, os, types, time, string, cStringIO, traceback, warnings
try: try:
import codecs import codecs
except ImportError: except ImportError:
@ -46,12 +46,17 @@ except ImportError:
__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>" __author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
__status__ = "production" __status__ = "production"
__version__ = "0.5.0.8" __version__ = "0.5.0.9"
__date__ = "27 April 2009" __date__ = "09 October 2009"
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Miscellaneous module data # Miscellaneous module data
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
try:
unicode
_unicode = True
except NameError:
_unicode = False
# #
# _srcfile is used when walking the stack to check when we've got the first # _srcfile is used when walking the stack to check when we've got the first
@ -59,7 +64,7 @@ __date__ = "27 April 2009"
# #
if hasattr(sys, 'frozen'): #support for py2exe if hasattr(sys, 'frozen'): #support for py2exe
_srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:]) _srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])
elif string.lower(__file__[-4:]) in ['.pyc', '.pyo']: elif __file__[-4:].lower() in ['.pyc', '.pyo']:
_srcfile = __file__[:-4] + '.py' _srcfile = __file__[:-4] + '.py'
else: else:
_srcfile = __file__ _srcfile = __file__
@ -71,7 +76,7 @@ def currentframe():
try: try:
raise Exception raise Exception
except: except:
return sys.exc_traceback.tb_frame.f_back return sys.exc_info()[2].tb_frame.f_back
if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3) if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
# done filching # done filching
@ -255,9 +260,7 @@ class LogRecord:
# 'Value is %d' instead of 'Value is 0'. # 'Value is %d' instead of 'Value is 0'.
# For the use case of passing a dictionary, this should not be a # For the use case of passing a dictionary, this should not be a
# problem. # problem.
if args and len(args) == 1 and ( if args and len(args) == 1 and isinstance(args[0], dict) and args[0]:
type(args[0]) == types.DictType
) and args[0]:
args = args[0] args = args[0]
self.args = args self.args = args
self.levelname = getLevelName(level) self.levelname = getLevelName(level)
@ -306,11 +309,11 @@ class LogRecord:
Return the message for this LogRecord after merging any user-supplied Return the message for this LogRecord after merging any user-supplied
arguments with the message. arguments with the message.
""" """
if not hasattr(types, "UnicodeType"): #if no unicode support... if not _unicode: #if no unicode support...
msg = str(self.msg) msg = str(self.msg)
else: else:
msg = self.msg msg = self.msg
if type(msg) not in (types.UnicodeType, types.StringType): if not isinstance(msg, basestring):
try: try:
msg = str(self.msg) msg = str(self.msg)
except UnicodeError: except UnicodeError:
@ -447,7 +450,7 @@ class Formatter:
formatException() and appended to the message. formatException() and appended to the message.
""" """
record.message = record.getMessage() record.message = record.getMessage()
if string.find(self._fmt,"%(asctime)") >= 0: if self._fmt.find("%(asctime)") >= 0:
record.asctime = self.formatTime(record, self.datefmt) record.asctime = self.formatTime(record, self.datefmt)
s = self._fmt % record.__dict__ s = self._fmt % record.__dict__
if record.exc_info: if record.exc_info:
@ -541,7 +544,7 @@ class Filter:
return 1 return 1
elif self.name == record.name: elif self.name == record.name:
return 1 return 1
elif string.find(record.name, self.name, 0, self.nlen) != 0: elif record.name.find(self.name, 0, self.nlen) != 0:
return 0 return 0
return (record.name[self.nlen] == ".") return (record.name[self.nlen] == ".")
@ -667,8 +670,8 @@ class Handler(Filterer):
This version is intended to be implemented by subclasses and so This version is intended to be implemented by subclasses and so
raises a NotImplementedError. raises a NotImplementedError.
""" """
raise NotImplementedError, 'emit must be implemented '\ raise NotImplementedError('emit must be implemented '
'by Handler subclasses' 'by Handler subclasses')
def handle(self, record): def handle(self, record):
""" """
@ -781,7 +784,7 @@ class StreamHandler(Handler):
msg = self.format(record) msg = self.format(record)
stream = self.stream stream = self.stream
fs = "%s\n" fs = "%s\n"
if not hasattr(types, "UnicodeType"): #if no unicode support... if not _unicode: #if no unicode support...
stream.write(fs % msg) stream.write(fs % msg)
else: else:
try: try:
@ -903,8 +906,8 @@ def setLoggerClass(klass):
""" """
if klass != Logger: if klass != Logger:
if not issubclass(klass, Logger): if not issubclass(klass, Logger):
raise TypeError, "logger not derived from logging.Logger: " + \ raise TypeError("logger not derived from logging.Logger: "
klass.__name__ + klass.__name__)
global _loggerClass global _loggerClass
_loggerClass = klass _loggerClass = klass
@ -967,7 +970,7 @@ class Manager:
from the specified logger to the root of the logger hierarchy. from the specified logger to the root of the logger hierarchy.
""" """
name = alogger.name name = alogger.name
i = string.rfind(name, ".") i = name.rfind(".")
rv = None rv = None
while (i > 0) and not rv: while (i > 0) and not rv:
substr = name[:i] substr = name[:i]
@ -980,7 +983,7 @@ class Manager:
else: else:
assert isinstance(obj, PlaceHolder) assert isinstance(obj, PlaceHolder)
obj.append(alogger) obj.append(alogger)
i = string.rfind(name, ".", 0, i - 1) i = name.rfind(".", 0, i - 1)
if not rv: if not rv:
rv = self.root rv = self.root
alogger.parent = rv alogger.parent = rv
@ -994,7 +997,6 @@ class Manager:
namelen = len(name) namelen = len(name)
for c in ph.loggerMap.keys(): for c in ph.loggerMap.keys():
#The if means ... if not c.parent.name.startswith(nm) #The if means ... if not c.parent.name.startswith(nm)
#if string.find(c.parent.name, nm) <> 0:
if c.parent.name[:namelen] != name: if c.parent.name[:namelen] != name:
alogger.parent = c.parent alogger.parent = c.parent
c.parent = alogger c.parent = alogger
@ -1090,7 +1092,7 @@ class Logger(Filterer):
""" """
Convenience method for logging an ERROR with exception information. Convenience method for logging an ERROR with exception information.
""" """
self.error(*((msg,) + args), **{'exc_info': 1}) self.error(msg, exc_info=1, *args)
def critical(self, msg, *args, **kwargs): def critical(self, msg, *args, **kwargs):
""" """
@ -1115,9 +1117,9 @@ class Logger(Filterer):
logger.log(level, "We have a %s", "mysterious problem", exc_info=1) logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
""" """
if type(level) != types.IntType: if not isinstance(level, int):
if raiseExceptions: if raiseExceptions:
raise TypeError, "level must be an integer" raise TypeError("level must be an integer")
else: else:
return return
if self.isEnabledFor(level): if self.isEnabledFor(level):
@ -1173,7 +1175,7 @@ class Logger(Filterer):
else: else:
fn, lno, func = "(unknown file)", 0, "(unknown function)" fn, lno, func = "(unknown file)", 0, "(unknown function)"
if exc_info: if exc_info:
if type(exc_info) != types.TupleType: if not isinstance(exc_info, tuple):
exc_info = sys.exc_info() exc_info = sys.exc_info()
record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra) record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
self.handle(record) self.handle(record)
@ -1449,7 +1451,7 @@ def critical(msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.critical(*((msg,)+args), **kwargs) root.critical(msg, *args, **kwargs)
fatal = critical fatal = critical
@ -1459,14 +1461,14 @@ def error(msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.error(*((msg,)+args), **kwargs) root.error(msg, *args, **kwargs)
def exception(msg, *args): def exception(msg, *args):
""" """
Log a message with severity 'ERROR' on the root logger, Log a message with severity 'ERROR' on the root logger,
with exception information. with exception information.
""" """
error(*((msg,)+args), **{'exc_info': 1}) error(msg, exc_info=1, *args)
def warning(msg, *args, **kwargs): def warning(msg, *args, **kwargs):
""" """
@ -1474,7 +1476,7 @@ def warning(msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.warning(*((msg,)+args), **kwargs) root.warning(msg, *args, **kwargs)
warn = warning warn = warning
@ -1484,7 +1486,7 @@ def info(msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.info(*((msg,)+args), **kwargs) root.info(msg, *args, **kwargs)
def debug(msg, *args, **kwargs): def debug(msg, *args, **kwargs):
""" """
@ -1492,7 +1494,7 @@ def debug(msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.debug(*((msg,)+args), **kwargs) root.debug(msg, *args, **kwargs)
def log(level, msg, *args, **kwargs): def log(level, msg, *args, **kwargs):
""" """
@ -1500,7 +1502,7 @@ def log(level, msg, *args, **kwargs):
""" """
if len(root.handlers) == 0: if len(root.handlers) == 0:
basicConfig() basicConfig()
root.log(*((level, msg)+args), **kwargs) root.log(level, msg, *args, **kwargs)
def disable(level): def disable(level):
""" """

View File

@ -19,15 +19,12 @@ Configuration functions for the logging package for Python. The core package
is based on PEP 282 and comments thereto in comp.lang.python, and influenced is based on PEP 282 and comments thereto in comp.lang.python, and influenced
by Apache's log4j system. by Apache's log4j system.
Should work under Python versions >= 1.5.2, except that source line Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
information is not available unless 'sys._getframe()' is.
Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging' and log away! To use, simply 'import logging' and log away!
""" """
import sys, logging, logging.handlers, string, socket, struct, os, traceback, types import sys, logging, logging.handlers, socket, struct, os, traceback
try: try:
import thread import thread
@ -52,7 +49,7 @@ else:
# _listener holds the server object doing the listening # _listener holds the server object doing the listening
_listener = None _listener = None
def fileConfig(fname, defaults=None, disable_existing_loggers=1): def fileConfig(fname, defaults=None, disable_existing_loggers=True):
""" """
Read the logging configuration from a ConfigParser-format file. Read the logging configuration from a ConfigParser-format file.
@ -89,7 +86,7 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=1):
def _resolve(name): def _resolve(name):
"""Resolve a dotted name to a global object.""" """Resolve a dotted name to a global object."""
name = string.split(name, '.') name = name.split('.')
used = name.pop(0) used = name.pop(0)
found = __import__(used) found = __import__(used)
for n in name: for n in name:
@ -102,14 +99,14 @@ def _resolve(name):
return found return found
def _strip_spaces(alist): def _strip_spaces(alist):
return map(lambda x: string.strip(x), alist) return map(lambda x: x.strip(), alist)
def _create_formatters(cp): def _create_formatters(cp):
"""Create and return formatters""" """Create and return formatters"""
flist = cp.get("formatters", "keys") flist = cp.get("formatters", "keys")
if not len(flist): if not len(flist):
return {} return {}
flist = string.split(flist, ",") flist = flist.split(",")
flist = _strip_spaces(flist) flist = _strip_spaces(flist)
formatters = {} formatters = {}
for form in flist: for form in flist:
@ -138,7 +135,7 @@ def _install_handlers(cp, formatters):
hlist = cp.get("handlers", "keys") hlist = cp.get("handlers", "keys")
if not len(hlist): if not len(hlist):
return {} return {}
hlist = string.split(hlist, ",") hlist = hlist.split(",")
hlist = _strip_spaces(hlist) hlist = _strip_spaces(hlist)
handlers = {} handlers = {}
fixups = [] #for inter-handler references fixups = [] #for inter-handler references
@ -181,8 +178,8 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
# configure the root first # configure the root first
llist = cp.get("loggers", "keys") llist = cp.get("loggers", "keys")
llist = string.split(llist, ",") llist = llist.split(",")
llist = map(lambda x: string.strip(x), llist) llist = list(map(lambda x: x.strip(), llist))
llist.remove("root") llist.remove("root")
sectname = "logger_root" sectname = "logger_root"
root = logging.root root = logging.root
@ -195,7 +192,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
root.removeHandler(h) root.removeHandler(h)
hlist = cp.get(sectname, "handlers") hlist = cp.get(sectname, "handlers")
if len(hlist): if len(hlist):
hlist = string.split(hlist, ",") hlist = hlist.split(",")
hlist = _strip_spaces(hlist) hlist = _strip_spaces(hlist)
for hand in hlist: for hand in hlist:
log.addHandler(handlers[hand]) log.addHandler(handlers[hand])
@ -209,7 +206,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
#what's left in existing is the set of loggers #what's left in existing is the set of loggers
#which were in the previous configuration but #which were in the previous configuration but
#which are not in the new configuration. #which are not in the new configuration.
existing = root.manager.loggerDict.keys() existing = list(root.manager.loggerDict.keys())
#The list needs to be sorted so that we can #The list needs to be sorted so that we can
#avoid disabling child loggers of explicitly #avoid disabling child loggers of explicitly
#named loggers. With a sorted list it is easier #named loggers. With a sorted list it is easier
@ -247,7 +244,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
logger.disabled = 0 logger.disabled = 0
hlist = cp.get(sectname, "handlers") hlist = cp.get(sectname, "handlers")
if len(hlist): if len(hlist):
hlist = string.split(hlist, ",") hlist = hlist.split(",")
hlist = _strip_spaces(hlist) hlist = _strip_spaces(hlist)
for hand in hlist: for hand in hlist:
logger.addHandler(handlers[hand]) logger.addHandler(handlers[hand])
@ -278,7 +275,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
stopListening(). stopListening().
""" """
if not thread: if not thread:
raise NotImplementedError, "listen() needs threading to work" raise NotImplementedError("listen() needs threading to work")
class ConfigStreamHandler(StreamRequestHandler): class ConfigStreamHandler(StreamRequestHandler):
""" """
@ -321,7 +318,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
traceback.print_exc() traceback.print_exc()
os.remove(file) os.remove(file)
except socket.error, e: except socket.error, e:
if type(e.args) != types.TupleType: if not isinstance(e.args, tuple):
raise raise
else: else:
errcode = e.args[0] errcode = e.args[0]

View File

@ -24,7 +24,7 @@ Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging.handlers' and log away! To use, simply 'import logging.handlers' and log away!
""" """
import logging, socket, types, os, string, cPickle, struct, time, re import logging, socket, os, cPickle, struct, time, re
from stat import ST_DEV, ST_INO from stat import ST_DEV, ST_INO
try: try:
@ -41,6 +41,7 @@ DEFAULT_UDP_LOGGING_PORT = 9021
DEFAULT_HTTP_LOGGING_PORT = 9022 DEFAULT_HTTP_LOGGING_PORT = 9022
DEFAULT_SOAP_LOGGING_PORT = 9023 DEFAULT_SOAP_LOGGING_PORT = 9023
SYSLOG_UDP_PORT = 514 SYSLOG_UDP_PORT = 514
SYSLOG_TCP_PORT = 514
_MIDNIGHT = 24 * 60 * 60 # number of seconds in a day _MIDNIGHT = 24 * 60 * 60 # number of seconds in a day
@ -155,9 +156,9 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
If backupCount is > 0, when rollover is done, no more than backupCount If backupCount is > 0, when rollover is done, no more than backupCount
files are kept - the oldest ones are deleted. files are kept - the oldest ones are deleted.
""" """
def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0): def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False):
BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay) BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
self.when = string.upper(when) self.when = when.upper()
self.backupCount = backupCount self.backupCount = backupCount
self.utc = utc self.utc = utc
# Calculate the real rollover interval, which is just the number of # Calculate the real rollover interval, which is just the number of
@ -204,8 +205,6 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
self.interval = self.interval * interval # multiply by units requested self.interval = self.interval * interval # multiply by units requested
self.rolloverAt = self.computeRollover(int(time.time())) self.rolloverAt = self.computeRollover(int(time.time()))
#print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
def computeRollover(self, currentTime): def computeRollover(self, currentTime):
""" """
Work out the rollover time based on the specified time. Work out the rollover time based on the specified time.
@ -692,7 +691,8 @@ class SysLogHandler(logging.Handler):
"CRITICAL" : "critical" "CRITICAL" : "critical"
} }
def __init__(self, address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER): def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
facility=LOG_USER, socktype=socket.SOCK_DGRAM):
""" """
Initialize a handler. Initialize a handler.
@ -704,13 +704,16 @@ class SysLogHandler(logging.Handler):
self.address = address self.address = address
self.facility = facility self.facility = facility
if type(address) == types.StringType: self.socktype = socktype
if isinstance(address, basestring):
self.unixsocket = 1 self.unixsocket = 1
self._connect_unixsocket(address) self._connect_unixsocket(address)
else: else:
self.unixsocket = 0 self.unixsocket = 0
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket = socket.socket(socket.AF_INET, socktype)
if socktype == socket.SOCK_STREAM:
self.socket.connect(address)
self.formatter = None self.formatter = None
def _connect_unixsocket(self, address): def _connect_unixsocket(self, address):
@ -736,9 +739,9 @@ class SysLogHandler(logging.Handler):
priority_names mapping dictionaries are used to convert them to priority_names mapping dictionaries are used to convert them to
integers. integers.
""" """
if type(facility) == types.StringType: if isinstance(facility, basestring):
facility = self.facility_names[facility] facility = self.facility_names[facility]
if type(priority) == types.StringType: if isinstance(priority, basestring):
priority = self.priority_names[priority] priority = self.priority_names[priority]
return (facility << 3) | priority return (facility << 3) | priority
@ -783,8 +786,10 @@ class SysLogHandler(logging.Handler):
except socket.error: except socket.error:
self._connect_unixsocket(self.address) self._connect_unixsocket(self.address)
self.socket.send(msg) self.socket.send(msg)
else: elif self.socktype == socket.SOCK_DGRAM:
self.socket.sendto(msg, self.address) self.socket.sendto(msg, self.address)
else:
self.socket.sendall(msg)
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
raise raise
except: except:
@ -805,16 +810,16 @@ class SMTPHandler(logging.Handler):
for the credentials argument. for the credentials argument.
""" """
logging.Handler.__init__(self) logging.Handler.__init__(self)
if type(mailhost) == types.TupleType: if isinstance(mailhost, tuple):
self.mailhost, self.mailport = mailhost self.mailhost, self.mailport = mailhost
else: else:
self.mailhost, self.mailport = mailhost, None self.mailhost, self.mailport = mailhost, None
if type(credentials) == types.TupleType: if isinstance(credentials, tuple):
self.username, self.password = credentials self.username, self.password = credentials
else: else:
self.username = None self.username = None
self.fromaddr = fromaddr self.fromaddr = fromaddr
if type(toaddrs) == types.StringType: if isinstance(toaddrs, basestring):
toaddrs = [toaddrs] toaddrs = [toaddrs]
self.toaddrs = toaddrs self.toaddrs = toaddrs
self.subject = subject self.subject = subject
@ -865,7 +870,7 @@ class SMTPHandler(logging.Handler):
msg = self.format(record) msg = self.format(record)
msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
self.fromaddr, self.fromaddr,
string.join(self.toaddrs, ","), ",".join(self.toaddrs),
self.getSubject(record), self.getSubject(record),
formatdate(), msg) formatdate(), msg)
if self.username: if self.username:
@ -909,8 +914,8 @@ class NTEventLogHandler(logging.Handler):
logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE, logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
} }
except ImportError: except ImportError:
print "The Python Win32 extensions for NT (service, event "\ print("The Python Win32 extensions for NT (service, event "\
"logging) appear not to be available." "logging) appear not to be available.")
self._welu = None self._welu = None
def getMessageID(self, record): def getMessageID(self, record):
@ -988,9 +993,9 @@ class HTTPHandler(logging.Handler):
("GET" or "POST") ("GET" or "POST")
""" """
logging.Handler.__init__(self) logging.Handler.__init__(self)
method = string.upper(method) method = method.upper()
if method not in ["GET", "POST"]: if method not in ["GET", "POST"]:
raise ValueError, "method must be GET or POST" raise ValueError("method must be GET or POST")
self.host = host self.host = host
self.url = url self.url = url
self.method = method self.method = method
@ -1016,7 +1021,7 @@ class HTTPHandler(logging.Handler):
url = self.url url = self.url
data = urllib.urlencode(self.mapLogRecord(record)) data = urllib.urlencode(self.mapLogRecord(record))
if self.method == "GET": if self.method == "GET":
if (string.find(url, '?') >= 0): if (url.find('?') >= 0):
sep = '&' sep = '&'
else: else:
sep = '?' sep = '?'
@ -1024,7 +1029,7 @@ class HTTPHandler(logging.Handler):
h.putrequest(self.method, url) h.putrequest(self.method, url)
# support multiple hosts on one IP address... # support multiple hosts on one IP address...
# need to strip optional :port from host, if present # need to strip optional :port from host, if present
i = string.find(host, ":") i = host.find(":")
if i >= 0: if i >= 0:
host = host[:i] host = host[:i]
h.putheader("Host", host) h.putheader("Host", host)

View File

@ -398,6 +398,9 @@ Core and Builtins
Library Library
------- -------
- Issue #7086: Added TCP support to SysLogHandler, and tidied up some
anachronisms in the code which were a relic of 1.5.2 compatibility.
- Issue #7082: When falling back to the MIME 'name' parameter, the - Issue #7082: When falling back to the MIME 'name' parameter, the
correct place to look for it is the Content-Type header. correct place to look for it is the Content-Type header.