From 130ff0f9579162347fd8e8e9e63e8422aed97b12 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 22 Jul 2026 19:27:36 +0300 Subject: [PATCH] gh-59060: Support IPv6 in logging.handlers.DatagramHandler It always created an IPv4 socket, so sending to an IPv6 address failed and the log record was silently lost. Create a socket of the family of the resolved address if the host has no IPv4 address. Also add a timeout to the waits in DatagramHandlerTest. Co-Authored-By: Claude Opus 4.8 (1M context) --- Doc/library/logging.handlers.rst | 3 +++ Doc/whatsnew/3.16.rst | 5 ++++ Lib/logging/handlers.py | 10 ++++++++ Lib/test/test_logging.py | 23 ++++++++++++++++--- ...6-07-22-16-20-17.gh-issue-59060.1nZ8hJ.rst | 4 ++++ 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-22-16-20-17.gh-issue-59060.1nZ8hJ.rst diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst index 5152c7561fa1f2..35a68b1986be00 100644 --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -594,6 +594,9 @@ over UDP sockets. If ``port`` is specified as ``None``, a Unix domain socket is created using the value in ``host`` - otherwise, a UDP socket is created. + .. versionchanged:: next + Added support for IPv6. + .. method:: emit() Pickles the record's attribute dictionary and writes it to the socket in diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 662defa709a246..9f7fb51c96769f 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -349,6 +349,11 @@ logging before the rotation interval expires. (Contributed by Iván Márton and Serhiy Storchaka in :gh:`84649`.) +* :class:`~logging.handlers.DatagramHandler` now supports IPv6. + Previously it always created an IPv4 socket, so sending to an IPv6 address + failed and the log record was silently lost. + (Contributed by Serhiy Storchaka in :gh:`59060`.) + lzma ---- diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index a5394d2dbea649..0375c5b64d536d 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -758,6 +758,16 @@ def makeSocket(self): family = socket.AF_UNIX else: family = socket.AF_INET + # The host can have no IPv4 address, for example if it is an + # IPv6 address. Leave resolution errors to sendto(). + try: + infos = socket.getaddrinfo(self.host, self.port, + type=socket.SOCK_DGRAM) + except OSError: + pass + else: + if not any(info[0] == family for info in infos): + family = infos[0][0] s = socket.socket(family, socket.SOCK_DGRAM) return s diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 06b3aa66fc47a3..51fe8e02160f9c 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1982,7 +1982,7 @@ def setUp(self): server.ready.wait() hcls = logging.handlers.DatagramHandler if isinstance(server.server_address, tuple): - self.sock_hdlr = hcls('localhost', server.port) + self.sock_hdlr = hcls(self.address[0], server.port) else: self.sock_hdlr = hcls(server.server_address, None) self.log_output = '' @@ -2015,12 +2015,29 @@ def test_output(self): self.skipTest(self.server_exception) logger = logging.getLogger("udp") logger.error("spam") - self.handled.wait() + self.handled.wait(support.LONG_TIMEOUT) self.handled.clear() logger.error("eggs") - self.handled.wait() + self.handled.wait(support.LONG_TIMEOUT) self.assertEqual(self.log_output, "spam\neggs\n") +@unittest.skipUnless(socket_helper.IPV6_ENABLED, + 'IPv6 support required for this test.') +class IPv6DatagramHandlerTest(DatagramHandlerTest): + + """Test for DatagramHandler with IPv6 host.""" + + server_class = TestUDPServer + address = ('::1', 0) + + def setUp(self): + self.server_class.address_family = socket.AF_INET6 + super().setUp() + + def tearDown(self): + self.server_class.address_family = socket.AF_INET + super().tearDown() + @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") class UnixDatagramHandlerTest(DatagramHandlerTest): diff --git a/Misc/NEWS.d/next/Library/2026-07-22-16-20-17.gh-issue-59060.1nZ8hJ.rst b/Misc/NEWS.d/next/Library/2026-07-22-16-20-17.gh-issue-59060.1nZ8hJ.rst new file mode 100644 index 00000000000000..e5497c64c7e041 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-22-16-20-17.gh-issue-59060.1nZ8hJ.rst @@ -0,0 +1,4 @@ +:class:`logging.handlers.DatagramHandler` now supports IPv6: +it creates an IPv6 socket if the host has no IPv4 address. +Previously it always created an IPv4 socket, +so the log records were silently lost.