summaryrefslogtreecommitdiffstats
path: root/Lib/logging/handlers.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/logging/handlers.py')
-rw-r--r--Lib/logging/handlers.py136
1 files changed, 70 insertions, 66 deletions
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 756baf0..f8c7164 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1,4 +1,4 @@
-# Copyright 2001-2007 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
@@ -19,13 +19,13 @@ Additional handlers 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.
-Copyright (C) 2001-2009 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2010 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging.handlers' and log away!
"""
-import logging, socket, types, os, string, cPickle, struct, time, re
-from stat import ST_DEV, ST_INO
+import logging, socket, os, cPickle, struct, time, re
+from stat import ST_DEV, ST_INO, ST_MTIME
try:
import codecs
@@ -46,6 +46,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
@@ -107,8 +108,13 @@ class RotatingFileHandler(BaseRotatingHandler):
If maxBytes is zero, rollover never occurs.
"""
+ # If rotation/rollover is wanted, it doesn't make sense to use another
+ # mode. If for example 'w' were specified, then if there were multiple
+ # runs of the calling application, the logs from previous runs would be
+ # lost if the 'w' is respected, because the log file would be truncated
+ # on each run.
if maxBytes > 0:
- mode = 'a' # doesn't make sense otherwise!
+ mode = 'a'
BaseRotatingHandler.__init__(self, filename, mode, encoding, delay)
self.maxBytes = maxBytes
self.backupCount = backupCount
@@ -117,8 +123,9 @@ class RotatingFileHandler(BaseRotatingHandler):
"""
Do a rollover, as described in __init__().
"""
-
- self.stream.close()
+ if self.stream:
+ self.stream.close()
+ self.stream = None
if self.backupCount > 0:
for i in range(self.backupCount - 1, 0, -1):
sfn = "%s.%d" % (self.baseFilename, i)
@@ -160,9 +167,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
@@ -177,7 +184,6 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
#
# Case of the 'when' specifier is not important; lower or upper case
# will work.
- currentTime = int(time.time())
if self.when == 'S':
self.interval = 1 # one second
self.suffix = "%Y-%m-%d_%H-%M-%S"
@@ -208,9 +214,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
self.extMatch = re.compile(self.extMatch)
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)
+ if os.path.exists(filename):
+ t = os.stat(filename)[ST_MTIME]
+ else:
+ t = int(time.time())
+ self.rolloverAt = self.computeRollover(t)
def computeRollover(self, currentTime):
"""
@@ -317,6 +325,7 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
"""
if self.stream:
self.stream.close()
+ self.stream = None
# get the time that this sequence started at and make it a TimeTuple
t = self.rolloverAt - self.interval
if self.utc:
@@ -636,7 +645,8 @@ class SysLogHandler(logging.Handler):
LOG_NEWS = 7 # network news subsystem
LOG_UUCP = 8 # UUCP subsystem
LOG_CRON = 9 # clock daemon
- LOG_AUTHPRIV = 10 # security/authorization messages (private)
+ LOG_AUTHPRIV = 10 # security/authorization messages (private)
+ LOG_FTP = 11 # FTP daemon
# other codes through 15 reserved for system use
LOG_LOCAL0 = 16 # reserved for local use
@@ -668,6 +678,7 @@ class SysLogHandler(logging.Handler):
"authpriv": LOG_AUTHPRIV,
"cron": LOG_CRON,
"daemon": LOG_DAEMON,
+ "ftp": LOG_FTP,
"kern": LOG_KERN,
"lpr": LOG_LPR,
"mail": LOG_MAIL,
@@ -698,7 +709,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.
@@ -710,13 +722,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):
@@ -742,9 +757,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
@@ -773,20 +788,19 @@ class SysLogHandler(logging.Handler):
The record is formatted, and then sent to the syslog server. If
exception information is present, it is NOT sent to the server.
"""
- msg = self.format(record)
+ msg = self.format(record) + '\000'
"""
We need to convert record level to lowercase, maybe this will
change in the future.
"""
- msg = self.log_format_string % (
- self.encodePriority(self.facility,
- self.mapPriority(record.levelname)),
- msg)
- # Treat unicode messages as required by RFC 5424
- if _unicode and type(msg) is unicode:
+ prio = '<%d>' % self.encodePriority(self.facility,
+ self.mapPriority(record.levelname))
+ # Message is a string. Convert to bytes as required by RFC 5424
+ if type(msg) is unicode:
msg = msg.encode('utf-8')
if codecs:
msg = codecs.BOM_UTF8 + msg
+ msg = prio + msg
try:
if self.unixsocket:
try:
@@ -794,8 +808,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,7 +821,8 @@ class SMTPHandler(logging.Handler):
"""
A handler class which sends an SMTP email for each logging event.
"""
- def __init__(self, mailhost, fromaddr, toaddrs, subject, credentials=None):
+ def __init__(self, mailhost, fromaddr, toaddrs, subject,
+ credentials=None, secure=None):
"""
Initialize the handler.
@@ -813,22 +830,28 @@ class SMTPHandler(logging.Handler):
line of the email. To specify a non-standard SMTP port, use the
(host, port) tuple format for the mailhost argument. To specify
authentication credentials, supply a (username, password) tuple
- for the credentials argument.
+ for the credentials argument. To specify the use of a secure
+ protocol (TLS), pass in a tuple for the secure argument. This will
+ only be used when authentication credentials are supplied. The tuple
+ will be either an empty tuple, or a single-value tuple with the name
+ of a keyfile, or a 2-value tuple with the names of the keyfile and
+ certificate file. (This tuple is passed to the `starttls` method).
"""
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
+ self.secure = secure
def getSubject(self, record):
"""
@@ -839,24 +862,6 @@ class SMTPHandler(logging.Handler):
"""
return self.subject
- weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-
- monthname = [None,
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
-
- def date_time(self):
- """
- Return the current date and time formatted for a MIME header.
- Needed for Python 1.5.2 (no email package available)
- """
- year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time())
- s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
- self.weekdayname[wd],
- day, self.monthname[month], year,
- hh, mm, ss)
- return s
-
def emit(self, record):
"""
Emit a record.
@@ -865,10 +870,7 @@ class SMTPHandler(logging.Handler):
"""
try:
import smtplib
- try:
- from email.utils import formatdate
- except ImportError:
- formatdate = self.date_time
+ from email.utils import formatdate
port = self.mailport
if not port:
port = smtplib.SMTP_PORT
@@ -876,10 +878,14 @@ 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:
+ if self.secure is not None:
+ smtp.ehlo()
+ smtp.starttls(*self.secure)
+ smtp.ehlo()
smtp.login(self.username, self.password)
smtp.sendmail(self.fromaddr, self.toaddrs, msg)
smtp.quit()
@@ -920,8 +926,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):
@@ -999,9 +1005,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
@@ -1018,7 +1024,7 @@ class HTTPHandler(logging.Handler):
"""
Emit a record.
- Send the record to the Web server as an URL-encoded dictionary
+ Send the record to the Web server as a percent-encoded dictionary
"""
try:
import httplib, urllib
@@ -1027,7 +1033,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 = '?'
@@ -1035,7 +1041,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)
@@ -1043,9 +1049,7 @@ class HTTPHandler(logging.Handler):
h.putheader("Content-type",
"application/x-www-form-urlencoded")
h.putheader("Content-length", str(len(data)))
- h.endheaders()
- if self.method == "POST":
- h.send(data)
+ h.endheaders(data if self.method == "POST" else None)
h.getreply() #can't do anything with the result
except (KeyboardInterrupt, SystemExit):
raise