mirror of
https://github.com/python/cpython.git
synced 2025-08-31 22:18:28 +00:00
gh-126400: Add TCP socket timeout to SysLogHandler to prevent blocking (GH-126716)
Co-authored-by: Vinay Sajip <vinay_sajip@yahoo.co.uk>
This commit is contained in:
parent
002c4e2982
commit
fdcedfd3cf
4 changed files with 27 additions and 2 deletions
|
@ -613,7 +613,7 @@ 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=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER, socktype=socket.SOCK_DGRAM)
|
||||
.. class:: SysLogHandler(address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER, socktype=socket.SOCK_DGRAM, timeout=None)
|
||||
|
||||
Returns a new instance of the :class:`SysLogHandler` class intended to
|
||||
communicate with a remote Unix machine whose address is given by *address* in
|
||||
|
@ -626,6 +626,11 @@ supports sending logging messages to a remote or local Unix syslog.
|
|||
*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`.
|
||||
If *timeout* is specified, it sets a timeout (in seconds) for the socket operations.
|
||||
This can help prevent the program from hanging indefinitely if the syslog server is
|
||||
unreachable. By default, *timeout* is ``None``, meaning no timeout is applied.
|
||||
|
||||
|
||||
|
||||
Note that if your server is not listening on UDP port 514,
|
||||
:class:`SysLogHandler` may appear not to work. In that case, check what
|
||||
|
@ -645,6 +650,8 @@ supports sending logging messages to a remote or local Unix syslog.
|
|||
.. versionchanged:: 3.2
|
||||
*socktype* was added.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
*timeout* was added.
|
||||
|
||||
.. method:: close()
|
||||
|
||||
|
|
|
@ -855,7 +855,7 @@ class SysLogHandler(logging.Handler):
|
|||
}
|
||||
|
||||
def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
|
||||
facility=LOG_USER, socktype=None):
|
||||
facility=LOG_USER, socktype=None, timeout=None):
|
||||
"""
|
||||
Initialize a handler.
|
||||
|
||||
|
@ -872,6 +872,7 @@ class SysLogHandler(logging.Handler):
|
|||
self.address = address
|
||||
self.facility = facility
|
||||
self.socktype = socktype
|
||||
self.timeout = timeout
|
||||
self.socket = None
|
||||
self.createSocket()
|
||||
|
||||
|
@ -933,6 +934,8 @@ class SysLogHandler(logging.Handler):
|
|||
err = sock = None
|
||||
try:
|
||||
sock = socket.socket(af, socktype, proto)
|
||||
if self.timeout:
|
||||
sock.settimeout(self.timeout)
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
sock.connect(sa)
|
||||
break
|
||||
|
|
|
@ -22,6 +22,7 @@ import logging
|
|||
import logging.handlers
|
||||
import logging.config
|
||||
|
||||
|
||||
import codecs
|
||||
import configparser
|
||||
import copy
|
||||
|
@ -2095,6 +2096,18 @@ class SysLogHandlerTest(BaseTest):
|
|||
self.handled.wait(support.LONG_TIMEOUT)
|
||||
self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
|
||||
|
||||
@patch('socket.socket')
|
||||
def test_tcp_timeout(self, mock_socket):
|
||||
instance_mock_sock = mock_socket.return_value
|
||||
instance_mock_sock.connect.side_effect = socket.timeout
|
||||
|
||||
with self.assertRaises(socket.timeout):
|
||||
logging.handlers.SysLogHandler(address=('localhost', 514),
|
||||
socktype=socket.SOCK_STREAM,
|
||||
timeout=1)
|
||||
|
||||
instance_mock_sock.close.assert_called()
|
||||
|
||||
@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
|
||||
class UnixSysLogHandlerTest(SysLogHandlerTest):
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Add a socket *timeout* keyword argument to
|
||||
:class:`logging.handlers.SysLogHandler`.
|
Loading…
Add table
Add a link
Reference in a new issue