diff -r 719c11b6b6ff Lib/logging/__init__.py --- a/Lib/logging/__init__.py Wed Apr 06 09:50:03 2016 +0300 +++ b/Lib/logging/__init__.py Thu Apr 07 18:29:49 2016 +0300 @@ -35,7 +35,7 @@ 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'makeLogRecord', 'setLoggerClass', 'shutdown', 'warn', 'warning', 'getLogRecordFactory', 'setLogRecordFactory', - 'lastResort', 'raiseExceptions'] + 'lastResort', 'raiseExceptions', 'SafeHandler'] try: import threading @@ -935,7 +935,25 @@ finally: del t, v, tb -class StreamHandler(Handler): + +class SafeHandler(Handler): + """ + This class is the same as Handler except that it call handleError in case of exception during + an emit. + """ + def handle(self, record): + rv = self.filter(record) + if rv: + self.acquire() + try: + self.emit(record) + except Exception: + self.handleError(record) + finally: + self.release() + return rv + +class StreamHandler(SafeHandler): """ A handler class which writes logging records, appropriately formatted, to a stream. Note that this class does not close the stream, as @@ -977,14 +995,11 @@ has an 'encoding' attribute, it is used to determine how to do the output to the stream. """ - try: - msg = self.format(record) - stream = self.stream - stream.write(msg) - stream.write(self.terminator) - self.flush() - except Exception: - self.handleError(record) + msg = self.format(record) + stream = self.stream + stream.write(msg) + stream.write(self.terminator) + self.flush() class FileHandler(StreamHandler): """ diff -r 719c11b6b6ff Lib/logging/handlers.py --- a/Lib/logging/handlers.py Wed Apr 06 09:50:03 2016 +0300 +++ b/Lib/logging/handlers.py Thu Apr 07 18:29:49 2016 +0300 @@ -67,12 +67,9 @@ Output the record to the file, catering for rollover as described in doRollover(). """ - try: - if self.shouldRollover(record): - self.doRollover() - logging.FileHandler.emit(self, record) - except Exception: - self.handleError(record) + if self.shouldRollover(record): + self.doRollover() + logging.FileHandler.emit(self, record) def rotation_filename(self, default_name): """ @@ -479,7 +476,7 @@ logging.FileHandler.emit(self, record) -class SocketHandler(logging.Handler): +class SocketHandler(logging.SafeHandler): """ A handler class which writes logging records, in pickle format, to a streaming socket. The socket is kept open across logging calls. @@ -500,7 +497,7 @@ occurs, the socket is silently closed and then reopened on the next logging call. """ - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) self.host = host self.port = port if port is None: @@ -615,7 +612,7 @@ self.sock.close() self.sock = None #try to reconnect next time else: - logging.Handler.handleError(self, record) + logging.SafeHandler.handleError(self, record) def emit(self, record): """ @@ -626,11 +623,8 @@ If there was a problem with the socket, re-establishes the socket. """ - try: - s = self.makePickle(record) - self.send(s) - except Exception: - self.handleError(record) + s = self.makePickle(record) + self.send(s) def close(self): """ @@ -642,7 +636,7 @@ if sock: self.sock = None sock.close() - logging.Handler.close(self) + logging.SafeHandler.close(self) finally: self.release() @@ -688,7 +682,7 @@ self.createSocket() self.sock.sendto(s, self.address) -class SysLogHandler(logging.Handler): +class SysLogHandler(logging.SafeHandler): """ A handler class which sends formatted logging records to a syslog server. Based on Sam Rushing's syslog module: @@ -804,7 +798,7 @@ socktype of None, in which case socket.SOCK_DGRAM will be used, falling back to socket.SOCK_STREAM. """ - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) self.address = address self.facility = facility @@ -867,7 +861,7 @@ self.acquire() try: self.socket.close() - logging.Handler.close(self) + logging.SafeHandler.close(self) finally: self.release() @@ -891,36 +885,33 @@ The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - try: - msg = self.format(record) - if self.ident: - msg = self.ident + msg - if self.append_nul: - msg += '\000' + msg = self.format(record) + if self.ident: + msg = self.ident + msg + if self.append_nul: + msg += '\000' - # We need to convert record level to lowercase, maybe this will - # change in the future. - prio = '<%d>' % self.encodePriority(self.facility, - self.mapPriority(record.levelname)) - prio = prio.encode('utf-8') - # Message is a string. Convert to bytes as required by RFC 5424 - msg = msg.encode('utf-8') - msg = prio + msg - if self.unixsocket: - try: - self.socket.send(msg) - except OSError: - self.socket.close() - self._connect_unixsocket(self.address) - self.socket.send(msg) - elif self.socktype == socket.SOCK_DGRAM: - self.socket.sendto(msg, self.address) - else: - self.socket.sendall(msg) - except Exception: - self.handleError(record) + # We need to convert record level to lowercase, maybe this will + # change in the future. + prio = '<%d>' % self.encodePriority(self.facility, + self.mapPriority(record.levelname)) + prio = prio.encode('utf-8') + # Message is a string. Convert to bytes as required by RFC 5424 + msg = msg.encode('utf-8') + msg = prio + msg + if self.unixsocket: + try: + self.socket.send(msg) + except OSError: + self.socket.close() + self._connect_unixsocket(self.address) + self.socket.send(msg) + elif self.socktype == socket.SOCK_DGRAM: + self.socket.sendto(msg, self.address) + else: + self.socket.sendall(msg) -class SMTPHandler(logging.Handler): +class SMTPHandler(logging.SafeHandler): """ A handler class which sends an SMTP email for each logging event. """ @@ -942,7 +933,7 @@ A timeout in seconds can be specified for the SMTP connection (the default is one second). """ - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) if isinstance(mailhost, (list, tuple)): self.mailhost, self.mailport = mailhost else: @@ -974,33 +965,30 @@ Format the record and send it to the specified addressees. """ - try: - import smtplib - from email.message import EmailMessage - import email.utils + import smtplib + from email.message import EmailMessage + import email.utils - port = self.mailport - if not port: - port = smtplib.SMTP_PORT - smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) - msg = EmailMessage() - msg['From'] = self.fromaddr - msg['To'] = ','.join(self.toaddrs) - msg['Subject'] = self.getSubject(record) - msg['Date'] = email.utils.localtime() - msg.set_content(self.format(record)) - if self.username: - if self.secure is not None: - smtp.ehlo() - smtp.starttls(*self.secure) - smtp.ehlo() - smtp.login(self.username, self.password) - smtp.send_message(msg) - smtp.quit() - except Exception: - self.handleError(record) + port = self.mailport + if not port: + port = smtplib.SMTP_PORT + smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout) + msg = EmailMessage() + msg['From'] = self.fromaddr + msg['To'] = ','.join(self.toaddrs) + msg['Subject'] = self.getSubject(record) + msg['Date'] = email.utils.localtime() + msg.set_content(self.format(record)) + if self.username: + if self.secure is not None: + smtp.ehlo() + smtp.starttls(*self.secure) + smtp.ehlo() + smtp.login(self.username, self.password) + smtp.send_message(msg) + smtp.quit() -class NTEventLogHandler(logging.Handler): +class NTEventLogHandler(logging.SafeHandler): """ A handler class which sends events to the NT Event Log. Adds a registry entry for the specified application name. If no dllname is @@ -1011,7 +999,7 @@ which contains the message definitions you want to use in the event log. """ def __init__(self, appname, dllname=None, logtype="Application"): - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) try: import win32evtlogutil, win32evtlog self.appname = appname @@ -1076,14 +1064,11 @@ log the message in the NT event log. """ if self._welu: - try: - id = self.getMessageID(record) - cat = self.getEventCategory(record) - type = self.getEventType(record) - msg = self.format(record) - self._welu.ReportEvent(self.appname, id, cat, type, [msg]) - except Exception: - self.handleError(record) + id = self.getMessageID(record) + cat = self.getEventCategory(record) + type = self.getEventType(record) + msg = self.format(record) + self._welu.ReportEvent(self.appname, id, cat, type, [msg]) def close(self): """ @@ -1096,9 +1081,9 @@ DLL name. """ #self._welu.RemoveSourceFromRegistry(self.appname, self.logtype) - logging.Handler.close(self) + logging.SafeHandler.close(self) -class HTTPHandler(logging.Handler): +class HTTPHandler(logging.SafeHandler): """ A class which sends records to a Web server, using either GET or POST semantics. @@ -1109,7 +1094,7 @@ Initialize the instance with the host, the request URL, and the method ("GET" or "POST") """ - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) method = method.upper() if method not in ["GET", "POST"]: raise ValueError("method must be GET or POST") @@ -1137,43 +1122,40 @@ Send the record to the Web server as a percent-encoded dictionary """ - try: - import http.client, urllib.parse - host = self.host - if self.secure: - h = http.client.HTTPSConnection(host, context=self.context) + import http.client, urllib.parse + host = self.host + if self.secure: + h = http.client.HTTPSConnection(host, context=self.context) + else: + h = http.client.HTTPConnection(host) + url = self.url + data = urllib.parse.urlencode(self.mapLogRecord(record)) + if self.method == "GET": + if (url.find('?') >= 0): + sep = '&' else: - h = http.client.HTTPConnection(host) - url = self.url - data = urllib.parse.urlencode(self.mapLogRecord(record)) - if self.method == "GET": - if (url.find('?') >= 0): - sep = '&' - else: - sep = '?' - url = url + "%c%s" % (sep, data) - h.putrequest(self.method, url) - # support multiple hosts on one IP address... - # need to strip optional :port from host, if present - i = host.find(":") - if i >= 0: - host = host[:i] - h.putheader("Host", host) - if self.method == "POST": - h.putheader("Content-type", - "application/x-www-form-urlencoded") - h.putheader("Content-length", str(len(data))) - if self.credentials: - import base64 - s = ('u%s:%s' % self.credentials).encode('utf-8') - s = 'Basic ' + base64.b64encode(s).strip() - h.putheader('Authorization', s) - h.endheaders() - if self.method == "POST": - h.send(data.encode('utf-8')) - h.getresponse() #can't do anything with the result - except Exception: - self.handleError(record) + sep = '?' + url = url + "%c%s" % (sep, data) + h.putrequest(self.method, url) + # support multiple hosts on one IP address... + # need to strip optional :port from host, if present + i = host.find(":") + if i >= 0: + host = host[:i] + h.putheader("Host", host) + if self.method == "POST": + h.putheader("Content-type", + "application/x-www-form-urlencoded") + h.putheader("Content-length", str(len(data))) + if self.credentials: + import base64 + s = ('u%s:%s' % self.credentials).encode('utf-8') + s = 'Basic ' + base64.b64encode(s).strip() + h.putheader('Authorization', s) + h.endheaders() + if self.method == "POST": + h.send(data.encode('utf-8')) + h.getresponse() #can't do anything with the result class BufferingHandler(logging.Handler): """ @@ -1295,7 +1277,7 @@ self.release() -class QueueHandler(logging.Handler): +class QueueHandler(logging.SafeHandler): """ This handler sends events to a queue. Typically, it would be used together with a multiprocessing Queue to centralise logging to file in one process @@ -1310,7 +1292,7 @@ """ Initialise an instance, using the passed queue. """ - logging.Handler.__init__(self) + logging.SafeHandler.__init__(self) self.queue = queue def enqueue(self, record): @@ -1354,10 +1336,7 @@ Writes the LogRecord to the queue, preparing it for pickling first. """ - try: - self.enqueue(self.prepare(record)) - except Exception: - self.handleError(record) + self.enqueue(self.prepare(record)) if threading: class QueueListener(object):