mirror of https://github.com/python/cpython
logging: added support for Unix domain sockets to SocketHandler and DatagramHandler.
This commit is contained in:
parent
55798896a4
commit
5421f35d5e
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
@ -1425,21 +1438,46 @@ class SocketHandlerTest(BaseTest):
|
|||
self.root_logger.error('Nor this')
|
||||
|
||||
|
||||
@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)
|
||||
|
@ -1473,22 +1511,46 @@ class DatagramHandlerTest(BaseTest):
|
|||
self.assertEqual(self.log_output, "spam\neggs\n")
|
||||
|
||||
|
||||
@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)
|
||||
|
@ -1525,6 +1587,29 @@ class SysLogHandlerTest(BaseTest):
|
|||
self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
|
||||
|
||||
|
||||
@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__":
|
||||
|
|
Loading…
Reference in New Issue