8000 gh-126400: Add TCP socket timeout to SysLogHandler to prevent blocking by hodamarr · Pull Request #126716 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-126400: Add TCP socket timeout to SysLogHandler to prevent blocking #126716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Doc/library/logging.handlers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -613,9 +613,9 @@
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

Check warning on line 618 in Doc/library/logging.handlers.rst

View workflow job for this annotation

GitHub Actions / Docs / Docs

py:const reference target not found: LOG_USER [ref.const]
communicate with a remote Unix machine whose address is given by *address* in
the form of a ``(host, port)`` tuple. If *address* is not specified,
``('localhost', 514)`` is used. The address is used to open a socket. An
Expand All @@ -626,6 +626,11 @@
*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
Expand All @@ -645,6 +650,8 @@
.. versionchanged:: 3.2
*socktype* was added.

.. versionchanged:: 3.14
*timeout* was added.

.. method:: close()

Expand Down
5 changes: 4 additions & 1 deletion Lib/logging/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -872,6 +872,7 @@ def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
self.address = address
self.facility = facility
self.socktype = socktype
self.timeout = timeout
self.socket = None
self.createSocket()

Expand Down Expand Up @@ -933,6 +934,8 @@ def createSocket(self):
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
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import logging.handlers
import logging.config


import codecs
import configparser
import copy
Expand Down Expand Up @@ -2098,6 +2099,18 @@ def test_udp_reconnection(self):
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):

Expand Down
2 changes: 1 addition & 1 deletion Misc/NEWS.d/3.10.0b1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ result from ``entry_points()`` as deprecated.

..

.. gh: 47383
.. gh-issue: 47383
.. date: 2021-04-08-19-32-26
.. nonce: YI1hdL
.. section: Library
Expand Down
4 changes: 2 additions & 2 deletions Misc/NEWS.d/3.11.0b1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ planned). Patch by Alex Waygood.

..

.. gh: 78157
.. gh-issue: 78157
.. date: 2022-05-05-20-40-45
.. nonce: IA_9na
.. section: Library
Expand Down Expand Up @@ -1289,7 +1289,7 @@ Deprecate the chunk module.

..

.. gh: 91498
.. gh-issue: 91498
.. date: 2022-04-10-08-39-44
.. nonce: 8oII92
.. section: Library
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a socket *timeout* keyword argument to
:class:`logging.handlers.SysLogHandler`.
Loading
0