diff options
author | Hod <104125115+hodamarr@users.noreply.github.com> | 2025-01-29 19:37:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-29 19:37:43 (GMT) |
commit | fdcedfd3cf1a645634dee354ee349d966c56348f (patch) | |
tree | e1461e8306a174a43187433a1d8ad5b9b9c65e61 | |
parent | 002c4e2982910937f35a4b80ab94b07c3c16067f (diff) | |
download | cpython-fdcedfd3cf1a645634dee354ee349d966c56348f.zip cpython-fdcedfd3cf1a645634dee354ee349d966c56348f.tar.gz cpython-fdcedfd3cf1a645634dee354ee349d966c56348f.tar.bz2 |
gh-126400: Add TCP socket timeout to SysLogHandler to prevent blocking (GH-126716)
Co-authored-by: Vinay Sajip <vinay_sajip@yahoo.co.uk>
-rw-r--r-- | Doc/library/logging.handlers.rst | 9 | ||||
-rw-r--r-- | Lib/logging/handlers.py | 5 | ||||
-rw-r--r-- | Lib/test/test_logging.py | 13 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2025-01-29-13-37-18.gh-issue-126400.DaBaR3.rst | 2 |
4 files changed, 27 insertions, 2 deletions
diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 5a081f9..ffb5459 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -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() diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 1cba64f..017c9ab 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -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 diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 2e5f647..e34fe45 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -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): diff --git a/Misc/NEWS.d/next/Library/2025-01-29-13-37-18.gh-issue-126400.DaBaR3.rst b/Misc/NEWS.d/next/Library/2025-01-29-13-37-18.gh-issue-126400.DaBaR3.rst new file mode 100644 index 0000000..1532faf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-01-29-13-37-18.gh-issue-126400.DaBaR3.rst @@ -0,0 +1,2 @@ +Add a socket *timeout* keyword argument to +:class:`logging.handlers.SysLogHandler`. |