summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2009-10-10 20:32:36 (GMT)
committerVinay Sajip <vinay_sajip@yahoo.co.uk>2009-10-10 20:32:36 (GMT)
commit1c77b7f84c5fca050980854a677539ba377439dd (patch)
tree05297baa544790a3fff404e9fdb969b19e94427f
parent6e3dbbdf39f3b4eb6f18c0165e446df17218b7dc (diff)
downloadcpython-1c77b7f84c5fca050980854a677539ba377439dd.zip
cpython-1c77b7f84c5fca050980854a677539ba377439dd.tar.gz
cpython-1c77b7f84c5fca050980854a677539ba377439dd.tar.bz2
Issue #7086: Added TCP support to SysLogHandler and tidied up some anachronisms in the code.
-rw-r--r--Doc/library/logging.rst18
-rw-r--r--Lib/logging/__init__.py66
-rw-r--r--Lib/logging/config.py31
-rw-r--r--Lib/logging/handlers.py49
-rw-r--r--Misc/NEWS3
5 files changed, 90 insertions, 77 deletions
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
index ef2f34a..0614402 100644
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -764,12 +764,12 @@ functions.
Does basic configuration for the logging system by creating a
: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
- the root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
+ root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
:func:`error` and :func:`critical` will call :func:`basicConfig` automatically
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
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.
-.. class:: SysLogHandler([address[, facility]])
+.. class:: SysLogHandler([address[, facility[, socktype]]])
Returns a new instance of the :class:`SysLogHandler` class intended to
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,
- ``('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
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,
- :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()
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 092ebc3..0be6ed4 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -23,6 +23,8 @@ Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging' and log away!
"""
+import sys, os, time, cStringIO, traceback, warnings
+
__all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO',
'LogRecord', 'Logger', 'LoggerAdapter', 'NOTSET', 'NullHandler',
@@ -31,8 +33,6 @@ __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR',
'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass',
'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning']
-import sys, os, types, time, string, cStringIO, traceback, warnings
-
try:
import codecs
except ImportError:
@@ -46,12 +46,17 @@ except ImportError:
__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
__status__ = "production"
-__version__ = "0.5.0.8"
-__date__ = "27 April 2009"
+__version__ = "0.5.0.9"
+__date__ = "09 October 2009"
#---------------------------------------------------------------------------
# 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
@@ -59,7 +64,7 @@ __date__ = "27 April 2009"
#
if hasattr(sys, 'frozen'): #support for py2exe
_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'
else:
_srcfile = __file__
@@ -71,7 +76,7 @@ def currentframe():
try:
raise Exception
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)
# done filching
@@ -255,9 +260,7 @@ class LogRecord:
# 'Value is %d' instead of 'Value is 0'.
# For the use case of passing a dictionary, this should not be a
# problem.
- if args and len(args) == 1 and (
- type(args[0]) == types.DictType
- ) and args[0]:
+ if args and len(args) == 1 and isinstance(args[0], dict) and args[0]:
args = args[0]
self.args = args
self.levelname = getLevelName(level)
@@ -306,11 +309,11 @@ class LogRecord:
Return the message for this LogRecord after merging any user-supplied
arguments with the message.
"""
- if not hasattr(types, "UnicodeType"): #if no unicode support...
+ if not _unicode: #if no unicode support...
msg = str(self.msg)
else:
msg = self.msg
- if type(msg) not in (types.UnicodeType, types.StringType):
+ if not isinstance(msg, basestring):
try:
msg = str(self.msg)
except UnicodeError:
@@ -447,7 +450,7 @@ class Formatter:
formatException() and appended to the message.
"""
record.message = record.getMessage()
- if string.find(self._fmt,"%(asctime)") >= 0:
+ if self._fmt.find("%(asctime)") >= 0:
record.asctime = self.formatTime(record, self.datefmt)
s = self._fmt % record.__dict__
if record.exc_info:
@@ -541,7 +544,7 @@ class Filter:
return 1
elif self.name == record.name:
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 (record.name[self.nlen] == ".")
@@ -667,8 +670,8 @@ class Handler(Filterer):
This version is intended to be implemented by subclasses and so
raises a NotImplementedError.
"""
- raise NotImplementedError, 'emit must be implemented '\
- 'by Handler subclasses'
+ raise NotImplementedError('emit must be implemented '
+ 'by Handler subclasses')
def handle(self, record):
"""
@@ -781,7 +784,7 @@ class StreamHandler(Handler):
msg = self.format(record)
stream = self.stream
fs = "%s\n"
- if not hasattr(types, "UnicodeType"): #if no unicode support...
+ if not _unicode: #if no unicode support...
stream.write(fs % msg)
else:
try:
@@ -903,8 +906,8 @@ def setLoggerClass(klass):
"""
if klass != Logger:
if not issubclass(klass, Logger):
- raise TypeError, "logger not derived from logging.Logger: " + \
- klass.__name__
+ raise TypeError("logger not derived from logging.Logger: "
+ + klass.__name__)
global _loggerClass
_loggerClass = klass
@@ -967,7 +970,7 @@ class Manager:
from the specified logger to the root of the logger hierarchy.
"""
name = alogger.name
- i = string.rfind(name, ".")
+ i = name.rfind(".")
rv = None
while (i > 0) and not rv:
substr = name[:i]
@@ -980,7 +983,7 @@ class Manager:
else:
assert isinstance(obj, PlaceHolder)
obj.append(alogger)
- i = string.rfind(name, ".", 0, i - 1)
+ i = name.rfind(".", 0, i - 1)
if not rv:
rv = self.root
alogger.parent = rv
@@ -994,7 +997,6 @@ class Manager:
namelen = len(name)
for c in ph.loggerMap.keys():
#The if means ... if not c.parent.name.startswith(nm)
- #if string.find(c.parent.name, nm) <> 0:
if c.parent.name[:namelen] != name:
alogger.parent = c.parent
c.parent = alogger
@@ -1090,7 +1092,7 @@ class Logger(Filterer):
"""
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):
"""
@@ -1115,9 +1117,9 @@ class Logger(Filterer):
logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
"""
- if type(level) != types.IntType:
+ if not isinstance(level, int):
if raiseExceptions:
- raise TypeError, "level must be an integer"
+ raise TypeError("level must be an integer")
else:
return
if self.isEnabledFor(level):
@@ -1173,7 +1175,7 @@ class Logger(Filterer):
else:
fn, lno, func = "(unknown file)", 0, "(unknown function)"
if exc_info:
- if type(exc_info) != types.TupleType:
+ if not isinstance(exc_info, tuple):
exc_info = sys.exc_info()
record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)
self.handle(record)
@@ -1449,7 +1451,7 @@ def critical(msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.critical(*((msg,)+args), **kwargs)
+ root.critical(msg, *args, **kwargs)
fatal = critical
@@ -1459,14 +1461,14 @@ def error(msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.error(*((msg,)+args), **kwargs)
+ root.error(msg, *args, **kwargs)
def exception(msg, *args):
"""
Log a message with severity 'ERROR' on the root logger,
with exception information.
"""
- error(*((msg,)+args), **{'exc_info': 1})
+ error(msg, exc_info=1, *args)
def warning(msg, *args, **kwargs):
"""
@@ -1474,7 +1476,7 @@ def warning(msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.warning(*((msg,)+args), **kwargs)
+ root.warning(msg, *args, **kwargs)
warn = warning
@@ -1484,7 +1486,7 @@ def info(msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.info(*((msg,)+args), **kwargs)
+ root.info(msg, *args, **kwargs)
def debug(msg, *args, **kwargs):
"""
@@ -1492,7 +1494,7 @@ def debug(msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.debug(*((msg,)+args), **kwargs)
+ root.debug(msg, *args, **kwargs)
def log(level, msg, *args, **kwargs):
"""
@@ -1500,7 +1502,7 @@ def log(level, msg, *args, **kwargs):
"""
if len(root.handlers) == 0:
basicConfig()
- root.log(*((level, msg)+args), **kwargs)
+ root.log(level, msg, *args, **kwargs)
def disable(level):
"""
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 3017ae9..99403d2 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -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
by Apache's log4j system.
-Should work under Python versions >= 1.5.2, except that source line
-information is not available unless 'sys._getframe()' is.
-
-Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
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:
import thread
@@ -52,7 +49,7 @@ else:
# _listener holds the server object doing the listening
_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.
@@ -89,7 +86,7 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=1):
def _resolve(name):
"""Resolve a dotted name to a global object."""
- name = string.split(name, '.')
+ name = name.split('.')
used = name.pop(0)
found = __import__(used)
for n in name:
@@ -102,14 +99,14 @@ def _resolve(name):
return found
def _strip_spaces(alist):
- return map(lambda x: string.strip(x), alist)
+ return map(lambda x: x.strip(), alist)
def _create_formatters(cp):
"""Create and return formatters"""
flist = cp.get("formatters", "keys")
if not len(flist):
return {}
- flist = string.split(flist, ",")
+ flist = flist.split(",")
flist = _strip_spaces(flist)
formatters = {}
for form in flist:
@@ -138,7 +135,7 @@ def _install_handlers(cp, formatters):
hlist = cp.get("handlers", "keys")
if not len(hlist):
return {}
- hlist = string.split(hlist, ",")
+ hlist = hlist.split(",")
hlist = _strip_spaces(hlist)
handlers = {}
fixups = [] #for inter-handler references
@@ -181,8 +178,8 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
# configure the root first
llist = cp.get("loggers", "keys")
- llist = string.split(llist, ",")
- llist = map(lambda x: string.strip(x), llist)
+ llist = llist.split(",")
+ llist = list(map(lambda x: x.strip(), llist))
llist.remove("root")
sectname = "logger_root"
root = logging.root
@@ -195,7 +192,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
root.removeHandler(h)
hlist = cp.get(sectname, "handlers")
if len(hlist):
- hlist = string.split(hlist, ",")
+ hlist = hlist.split(",")
hlist = _strip_spaces(hlist)
for hand in hlist:
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
#which were in the previous configuration but
#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
#avoid disabling child loggers of explicitly
#named loggers. With a sorted list it is easier
@@ -247,7 +244,7 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
logger.disabled = 0
hlist = cp.get(sectname, "handlers")
if len(hlist):
- hlist = string.split(hlist, ",")
+ hlist = hlist.split(",")
hlist = _strip_spaces(hlist)
for hand in hlist:
logger.addHandler(handlers[hand])
@@ -278,7 +275,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
stopListening().
"""
if not thread:
- raise NotImplementedError, "listen() needs threading to work"
+ raise NotImplementedError("listen() needs threading to work")
class ConfigStreamHandler(StreamRequestHandler):
"""
@@ -321,7 +318,7 @@ def listen(port=DEFAULT_LOGGING_CONFIG_PORT):
traceback.print_exc()
os.remove(file)
except socket.error, e:
- if type(e.args) != types.TupleType:
+ if not isinstance(e.args, tuple):
raise
else:
errcode = e.args[0]
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 9b68b85..bdf82af 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -24,7 +24,7 @@ Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
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
try:
@@ -41,6 +41,7 @@ DEFAULT_UDP_LOGGING_PORT = 9021
DEFAULT_HTTP_LOGGING_PORT = 9022
DEFAULT_SOAP_LOGGING_PORT = 9023
SYSLOG_UDP_PORT = 514
+SYSLOG_TCP_PORT = 514
_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
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)
- self.when = string.upper(when)
+ self.when = when.upper()
self.backupCount = backupCount
self.utc = utc
# 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.rolloverAt = self.computeRollover(int(time.time()))
- #print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
-
def computeRollover(self, currentTime):
"""
Work out the rollover time based on the specified time.
@@ -692,7 +691,8 @@ class SysLogHandler(logging.Handler):
"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.
@@ -704,13 +704,16 @@ class SysLogHandler(logging.Handler):
self.address = address
self.facility = facility
- if type(address) == types.StringType:
+ self.socktype = socktype
+
+ if isinstance(address, basestring):
self.unixsocket = 1
self._connect_unixsocket(address)
else:
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
def _connect_unixsocket(self, address):
@@ -736,9 +739,9 @@ class SysLogHandler(logging.Handler):
priority_names mapping dictionaries are used to convert them to
integers.
"""
- if type(facility) == types.StringType:
+ if isinstance(facility, basestring):
facility = self.facility_names[facility]
- if type(priority) == types.StringType:
+ if isinstance(priority, basestring):
priority = self.priority_names[priority]
return (facility << 3) | priority
@@ -783,8 +786,10 @@ class SysLogHandler(logging.Handler):
except socket.error:
self._connect_unixsocket(self.address)
self.socket.send(msg)
- else:
+ elif self.socktype == socket.SOCK_DGRAM:
self.socket.sendto(msg, self.address)
+ else:
+ self.socket.sendall(msg)
except (KeyboardInterrupt, SystemExit):
raise
except:
@@ -805,16 +810,16 @@ class SMTPHandler(logging.Handler):
for the credentials argument.
"""
logging.Handler.__init__(self)
- if type(mailhost) == types.TupleType:
+ if isinstance(mailhost, tuple):
self.mailhost, self.mailport = mailhost
else:
self.mailhost, self.mailport = mailhost, None
- if type(credentials) == types.TupleType:
+ if isinstance(credentials, tuple):
self.username, self.password = credentials
else:
self.username = None
self.fromaddr = fromaddr
- if type(toaddrs) == types.StringType:
+ if isinstance(toaddrs, basestring):
toaddrs = [toaddrs]
self.toaddrs = toaddrs
self.subject = subject
@@ -865,7 +870,7 @@ class SMTPHandler(logging.Handler):
msg = self.format(record)
msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
self.fromaddr,
- string.join(self.toaddrs, ","),
+ ",".join(self.toaddrs),
self.getSubject(record),
formatdate(), msg)
if self.username:
@@ -909,8 +914,8 @@ class NTEventLogHandler(logging.Handler):
logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE,
}
except ImportError:
- print "The Python Win32 extensions for NT (service, event "\
- "logging) appear not to be available."
+ print("The Python Win32 extensions for NT (service, event "\
+ "logging) appear not to be available.")
self._welu = None
def getMessageID(self, record):
@@ -988,9 +993,9 @@ class HTTPHandler(logging.Handler):
("GET" or "POST")
"""
logging.Handler.__init__(self)
- method = string.upper(method)
+ method = method.upper()
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.url = url
self.method = method
@@ -1016,7 +1021,7 @@ class HTTPHandler(logging.Handler):
url = self.url
data = urllib.urlencode(self.mapLogRecord(record))
if self.method == "GET":
- if (string.find(url, '?') >= 0):
+ if (url.find('?') >= 0):
sep = '&'
else:
sep = '?'
@@ -1024,7 +1029,7 @@ class HTTPHandler(logging.Handler):
h.putrequest(self.method, url)
# support multiple hosts on one IP address...
# need to strip optional :port from host, if present
- i = string.find(host, ":")
+ i = host.find(":")
if i >= 0:
host = host[:i]
h.putheader("Host", host)
diff --git a/Misc/NEWS b/Misc/NEWS
index f3941c0..bdd657c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -398,6 +398,9 @@ Core and Builtins
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
correct place to look for it is the Content-Type header.