integ/python/python3.9/debian/patches/0001-bpo-44291-Fix-reconnec...

149 lines
5.3 KiB
Diff

From a28b8e4a9adeccdd0f68df07b29d5eba8c3d313d Mon Sep 17 00:00:00 2001
From: Kirill Pinchuk <192182+cybergrind@users.noreply.github.com>
Date: Thu, 5 Aug 2021 16:58:16 +0300
Subject: [PATCH] bpo-44291: Fix reconnection in logging.handlers.SysLogHandler
(GH-26490)
Right now SocketHandler and DatagramHandler implement such behavior:
1 - On close set self.socket = None
2 - When trying to send - make socket when it is None
SysLogHandler doesn't implement this behavior and when you close
the socket for some reason (eg. restart of uWSGI server on code change)
it leaves it in the closed state, then raises an error when you try to
send any message because it is closed.
--- Logging error ---
Traceback (most recent call last):
File "/usr/lib/python3.9/logging/handlers.py", line 959, in emit
self.socket.sendto(msg, self.address)
OSError: [Errno 9] Bad file descriptor
This patch adds reconnection logic for UDP/TCP sockets as well as UNIX
sockets.
Signed-off-by: Enzo Candotti <enzo.candotti@windriver.com>
---
Lib/logging/handlers.py | 63 ++++++++++++++++++++++++----------------
Lib/test/test_logging.py | 8 +++++
2 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 867ef4ebc7..ff8f9e534f 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -829,6 +829,36 @@ class SysLogHandler(logging.Handler):
self.address = address
self.facility = facility
self.socktype = socktype
+ self.socket = None
+ self.createSocket()
+
+ def _connect_unixsocket(self, address):
+ use_socktype = self.socktype
+ if use_socktype is None:
+ use_socktype = socket.SOCK_DGRAM
+ self.socket = socket.socket(socket.AF_UNIX, use_socktype)
+ try:
+ self.socket.connect(address)
+ # it worked, so set self.socktype to the used type
+ self.socktype = use_socktype
+ except OSError:
+ self.socket.close()
+ if self.socktype is not None:
+ # user didn't specify falling back, so fail
+ raise
+ use_socktype = socket.SOCK_STREAM
+ self.socket = socket.socket(socket.AF_UNIX, use_socktype)
+ try:
+ self.socket.connect(address)
+ # it worked, so set self.socktype to the used type
+ self.socktype = use_socktype
+ except OSError:
+ self.socket.close()
+ raise
+
+ def createSocket(self):
+ address = self.address
+ socktype = self.socktype
if isinstance(address, str):
self.unixsocket = True
@@ -865,30 +895,6 @@ class SysLogHandler(logging.Handler):
self.socket = sock
self.socktype = socktype
- def _connect_unixsocket(self, address):
- use_socktype = self.socktype
- if use_socktype is None:
- use_socktype = socket.SOCK_DGRAM
- self.socket = socket.socket(socket.AF_UNIX, use_socktype)
- try:
- self.socket.connect(address)
- # it worked, so set self.socktype to the used type
- self.socktype = use_socktype
- except OSError:
- self.socket.close()
- if self.socktype is not None:
- # user didn't specify falling back, so fail
- raise
- use_socktype = socket.SOCK_STREAM
- self.socket = socket.socket(socket.AF_UNIX, use_socktype)
- try:
- self.socket.connect(address)
- # it worked, so set self.socktype to the used type
- self.socktype = use_socktype
- except OSError:
- self.socket.close()
- raise
-
def encodePriority(self, facility, priority):
"""
Encode the facility and priority. You can pass in strings or
@@ -908,7 +914,10 @@ class SysLogHandler(logging.Handler):
"""
self.acquire()
try:
- self.socket.close()
+ sock = self.socket
+ if sock:
+ self.socket = None
+ sock.close()
logging.Handler.close(self)
finally:
self.release()
@@ -948,6 +957,10 @@ class SysLogHandler(logging.Handler):
# Message is a string. Convert to bytes as required by RFC 5424
msg = msg.encode('utf-8')
msg = prio + msg
+
+ if not self.socket:
+ self.createSocket()
+
if self.unixsocket:
try:
self.socket.send(msg)
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index a6cd291c9a..e795533775 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -1931,6 +1931,14 @@ class SysLogHandlerTest(BaseTest):
self.handled.wait()
self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m')
+ def test_udp_reconnection(self):
+ logger = logging.getLogger("slh")
+ self.sl_hdlr.close()
+ self.handled.clear()
+ logger.error("sp\xe4m")
+ self.handled.wait(0.1)
+ self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
+
@unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
class UnixSysLogHandlerTest(SysLogHandlerTest):
--
2.25.1