summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVinay Sajip <vinay_sajip@yahoo.co.uk>2013-09-27 17:18:28 (GMT)
committerVinay Sajip <vinay_sajip@yahoo.co.uk>2013-09-27 17:18:28 (GMT)
commit5421f35d5e215a69382f0c195c0c39c8b541eca7 (patch)
tree113a860e9f3758506e285490e0061ea472684469
parent55798896a4bd3f294755523d8237a56cacc4bf5c (diff)
downloadcpython-5421f35d5e215a69382f0c195c0c39c8b541eca7.zip
cpython-5421f35d5e215a69382f0c195c0c39c8b541eca7.tar.gz
cpython-5421f35d5e215a69382f0c195c0c39c8b541eca7.tar.bz2
logging: added support for Unix domain sockets to SocketHandler and DatagramHandler.
-rw-r--r--Doc/howto/logging.rst4
-rw-r--r--Doc/library/logging.handlers.rst6
-rw-r--r--Lib/logging/handlers.py20
-rw-r--r--Lib/test/test_logging.py118
-rw-r--r--Misc/NEWS3
5 files changed, 130 insertions, 21 deletions
diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst
index 165486a..c7a802a 100644
--- a/Doc/howto/logging.rst
+++ b/Doc/howto/logging.rst
@@ -900,10 +900,10 @@ provided:
disk files, rotating the log file at certain timed intervals.
#. :class:`~handlers.SocketHandler` instances send messages to TCP/IP
- sockets.
+ sockets. Since 3.4, Unix domain sockets are also supported.
#. :class:`~handlers.DatagramHandler` instances send messages to UDP
- sockets.
+ sockets. Since 3.4, Unix domain sockets are also supported.
#. :class:`~handlers.SMTPHandler` instances send messages to a designated
email address.
diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst
index 65e0b67..f52060a 100644
--- a/Doc/library/logging.handlers.rst
+++ b/Doc/library/logging.handlers.rst
@@ -381,6 +381,9 @@ sends logging output to a network socket. The base class uses a TCP socket.
Returns a new instance of the :class:`SocketHandler` class intended to
communicate with a remote machine whose address is given by *host* and *port*.
+ .. versionchanged:: 3.4
+ If ``port`` is specified as ``None``, a Unix domain socket is created
+ using the value in ``host`` - otherwise, a TCP socket is created.
.. method:: close()
@@ -466,6 +469,9 @@ over UDP sockets.
Returns a new instance of the :class:`DatagramHandler` class intended to
communicate with a remote machine whose address is given by *host* and *port*.
+ .. versionchanged:: 3.4
+ If ``port`` is specified as ``None``, a Unix domain socket is created
+ using the value in ``host`` - otherwise, a TCP socket is created.
.. method:: emit()
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 0ae6e45..b0b0a16 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -494,6 +494,10 @@ class SocketHandler(logging.Handler):
logging.Handler.__init__(self)
self.host = host
self.port = port
+ if port is None:
+ self.address = host
+ else:
+ self.address = (host, port)
self.sock = None
self.closeOnError = False
self.retryTime = None
@@ -509,7 +513,13 @@ class SocketHandler(logging.Handler):
A factory method which allows subclasses to define the precise
type of socket they want.
"""
- return socket.create_connection((self.host, self.port), timeout=timeout)
+ if self.port is not None:
+ result = socket.create_connection(self.address, timeout=timeout)
+ else:
+ result = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ result.settimeout(timeout)
+ result.connect(self.address)
+ return result
def createSocket(self):
"""
@@ -643,7 +653,11 @@ class DatagramHandler(SocketHandler):
The factory method of SocketHandler is here overridden to create
a UDP socket (SOCK_DGRAM).
"""
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ if self.port is None:
+ family = socket.AF_UNIX
+ else:
+ family = socket.AF_INET
+ s = socket.socket(family, socket.SOCK_DGRAM)
return s
def send(self, s):
@@ -656,7 +670,7 @@ class DatagramHandler(SocketHandler):
"""
if self.sock is None:
self.createSocket()
- self.sock.sendto(s, (self.host, self.port))
+ self.sock.sendto(s, self.address)
class SysLogHandler(logging.Handler):
"""
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 85e1898..cbdc78c 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -59,7 +59,9 @@ try:
import smtpd
from urllib.parse import urlparse, parse_qs
from socketserver import (ThreadingUDPServer, DatagramRequestHandler,
- ThreadingTCPServer, StreamRequestHandler)
+ ThreadingTCPServer, StreamRequestHandler,
+ ThreadingUnixStreamServer,
+ ThreadingUnixDatagramServer)
except ImportError:
threading = None
try:
@@ -854,6 +856,9 @@ if threading:
super(TestTCPServer, self).server_bind()
self.port = self.socket.getsockname()[1]
+ class TestUnixStreamServer(TestTCPServer):
+ address_family = socket.AF_UNIX
+
class TestUDPServer(ControlMixin, ThreadingUDPServer):
"""
A UDP server which is controllable using :class:`ControlMixin`.
@@ -901,6 +906,9 @@ if threading:
super(TestUDPServer, self).server_close()
self._closed = True
+ class TestUnixDatagramServer(TestUDPServer):
+ address_family = socket.AF_UNIX
+
# - end of server_helper section
@unittest.skipUnless(threading, 'Threading required for this test.')
@@ -1358,17 +1366,22 @@ class SocketHandlerTest(BaseTest):
"""Test for SocketHandler objects."""
+ server_class = TestTCPServer
+ address = ('localhost', 0)
+
def setUp(self):
"""Set up a TCP server to receive log messages, and a SocketHandler
pointing to that server's address and port."""
BaseTest.setUp(self)
- addr = ('localhost', 0)
- self.server = server = TestTCPServer(addr, self.handle_socket,
- 0.01)
+ self.server = server = self.server_class(self.address,
+ self.handle_socket, 0.01)
server.start()
server.ready.wait()
- self.sock_hdlr = logging.handlers.SocketHandler('localhost',
- server.port)
+ hcls = logging.handlers.SocketHandler
+ if isinstance(server.server_address, tuple):
+ self.sock_hdlr = hcls('localhost', server.port)
+ else:
+ self.sock_hdlr = hcls(server.server_address, None)
self.log_output = ''
self.root_logger.removeHandler(self.root_logger.handlers[0])
self.root_logger.addHandler(self.sock_hdlr)
@@ -1426,20 +1439,45 @@ class SocketHandlerTest(BaseTest):
@unittest.skipUnless(threading, 'Threading required for this test.')
+class UnixSocketHandlerTest(SocketHandlerTest):
+
+ """Test for SocketHandler with unix sockets."""
+
+ server_class = TestUnixStreamServer
+
+ def setUp(self):
+ # override the definition in the base class
+ fd, self.address = tempfile.mkstemp(prefix='test_logging_',
+ suffix='.sock')
+ os.close(fd)
+ os.remove(self.address) # just need a name - file can't be present
+ SocketHandlerTest.setUp(self)
+
+ def tearDown(self):
+ SocketHandlerTest.tearDown(self)
+ os.remove(self.address)
+
+@unittest.skipUnless(threading, 'Threading required for this test.')
class DatagramHandlerTest(BaseTest):
"""Test for DatagramHandler."""
+ server_class = TestUDPServer
+ address = ('localhost', 0)
+
def setUp(self):
"""Set up a UDP server to receive log messages, and a DatagramHandler
pointing to that server's address and port."""
BaseTest.setUp(self)
- addr = ('localhost', 0)
- self.server = server = TestUDPServer(addr, self.handle_datagram, 0.01)
+ self.server = server = self.server_class(self.address,
+ self.handle_datagram, 0.01)
server.start()
server.ready.wait()
- self.sock_hdlr = logging.handlers.DatagramHandler('localhost',
- server.port)
+ hcls = logging.handlers.DatagramHandler
+ if isinstance(server.server_address, tuple):
+ self.sock_hdlr = hcls('localhost', server.port)
+ else:
+ self.sock_hdlr = hcls(server.server_address, None)
self.log_output = ''
self.root_logger.removeHandler(self.root_logger.handlers[0])
self.root_logger.addHandler(self.sock_hdlr)
@@ -1474,21 +1512,45 @@ class DatagramHandlerTest(BaseTest):
@unittest.skipUnless(threading, 'Threading required for this test.')
+class UnixDatagramHandlerTest(DatagramHandlerTest):
+
+ """Test for DatagramHandler using Unix sockets."""
+
+ server_class = TestUnixDatagramServer
+
+ def setUp(self):
+ # override the definition in the base class
+ fd, self.address = tempfile.mkstemp(prefix='test_logging_',
+ suffix='.sock')
+ os.close(fd)
+ os.remove(self.address) # just need a name - file can't be present
+ DatagramHandlerTest.setUp(self)
+
+ def tearDown(self):
+ DatagramHandlerTest.tearDown(self)
+ os.remove(self.address)
+
+@unittest.skipUnless(threading, 'Threading required for this test.')
class SysLogHandlerTest(BaseTest):
"""Test for SysLogHandler using UDP."""
+ server_class = TestUDPServer
+ address = ('localhost', 0)
+
def setUp(self):
"""Set up a UDP server to receive log messages, and a SysLogHandler
pointing to that server's address and port."""
BaseTest.setUp(self)
- addr = ('localhost', 0)
- self.server = server = TestUDPServer(addr, self.handle_datagram,
- 0.01)
+ self.server = server = self.server_class(self.address,
+ self.handle_datagram, 0.01)
server.start()
server.ready.wait()
- self.sl_hdlr = logging.handlers.SysLogHandler(('localhost',
- server.port))
+ hcls = logging.handlers.SysLogHandler
+ if isinstance(server.server_address, tuple):
+ self.sl_hdlr = hcls(('localhost', server.port))
+ else:
+ self.sl_hdlr = hcls(server.server_address)
self.log_output = ''
self.root_logger.removeHandler(self.root_logger.handlers[0])
self.root_logger.addHandler(self.sl_hdlr)
@@ -1526,6 +1588,29 @@ class SysLogHandlerTest(BaseTest):
@unittest.skipUnless(threading, 'Threading required for this test.')
+class UnixSysLogHandlerTest(SysLogHandlerTest):
+
+ """Test for SysLogHandler with Unix sockets."""
+
+ server_class = TestUnixDatagramServer
+
+ def setUp(self):
+ # override the definition in the base class
+ fd, self.address = tempfile.mkstemp(prefix='test_logging_',
+ suffix='.sock')
+ os.close(fd)
+ os.remove(self.address) # just need a name - file can't be present
+ SysLogHandlerTest.setUp(self)
+
+ def tearDown(self):
+ SysLogHandlerTest.tearDown(self)
+ os.remove(self.address)
+
+# def test_output(self):
+# import pdb; pdb.set_trace()
+# SysLogHandlerTest.test_output(self)
+
+@unittest.skipUnless(threading, 'Threading required for this test.')
class HTTPHandlerTest(BaseTest):
"""Test for HTTPHandler."""
@@ -4034,7 +4119,8 @@ def test_main():
SMTPHandlerTest, FileHandlerTest, RotatingFileHandlerTest,
LastResortTest, LogRecordTest, ExceptionTest,
SysLogHandlerTest, HTTPHandlerTest, NTEventLogHandlerTest,
- TimedRotatingFileHandlerTest
+ TimedRotatingFileHandlerTest, UnixSocketHandlerTest,
+ UnixDatagramHandlerTest, UnixSysLogHandlerTest
)
if __name__ == "__main__":
diff --git a/Misc/NEWS b/Misc/NEWS
index 0b34293..6239614 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -15,6 +15,9 @@ Core and Builtins
Library
-------
+- logging: added support for Unix domain sockets to SocketHandler and
+ DatagramHandler.
+
- Issue #18996: TestCase.assertEqual() now more cleverly shorten differing
strings in error report.