]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-70990: Support bytes addresses of Unix sockets in SysLogHandler (GH-154500)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 24 Jul 2026 16:54:01 +0000 (19:54 +0300)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2026 16:54:01 +0000 (19:54 +0300)
Only a str address was recognized as a Unix domain socket.  A bytes
address, which socket.bind() accepts, fell through to the (host, port)
branch and raised ValueError.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Doc/library/logging.handlers.rst
Lib/logging/handlers.py
Lib/test/test_logging.py
Misc/NEWS.d/next/Library/2026-07-22-17-35-24.gh-issue-70990.xVHKwt.rst [new file with mode: 0644]

index 5152c7561fa1f26c9981785aae25c622e88be0c1..7230224b4fc5323e27025cb673c498919fd44f6c 100644 (file)
@@ -631,7 +631,8 @@ supports sending logging messages to a remote or local Unix syslog.
    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
    alternative to providing a ``(host, port)`` tuple is providing an address as a
-   string, for example '/dev/log'. In this case, a Unix domain socket is used to
+   string or a :class:`bytes` object, for example '/dev/log'.
+   In this case, a Unix domain socket is used to
    send the message to the syslog. If *facility* is not specified,
    :const:`LOG_USER` is used. The type of socket opened depends on the
    *socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus
@@ -664,6 +665,9 @@ supports sending logging messages to a remote or local Unix syslog.
    .. versionchanged:: 3.14
       *timeout* was added.
 
+   .. versionchanged:: next
+      *address* can now be a :class:`bytes` object.
+
    .. method:: close()
 
       Closes the socket to the remote host.
index a5394d2dbea6494d58d7855d2649e1d5c52eb45f..c78a30763d9fa089948eb8a367a94a8820b1950e 100644 (file)
@@ -886,8 +886,9 @@ class SysLogHandler(logging.Handler):
         """
         Initialize a handler.
 
-        If address is specified as a string, a UNIX socket is used. To log to a
-        local syslogd, "SysLogHandler(address="/dev/log")" can be used.
+        If address is specified as a string or bytes, a UNIX socket is used.
+        To log to a local syslogd, "SysLogHandler(address="/dev/log")" can be
+        used.
         If facility is not specified, LOG_USER is used. If socktype is
         specified as socket.SOCK_DGRAM or socket.SOCK_STREAM, that specific
         socket type will be used. For Unix sockets, you can also specify a
@@ -938,7 +939,7 @@ class SysLogHandler(logging.Handler):
         address = self.address
         socktype = self.socktype
 
-        if isinstance(address, str):
+        if not isinstance(address, (list, tuple)):
             self.unixsocket = True
             # Syslog server may be unavailable during handler initialisation.
             # C's openlog() function also ignores connection errors.
index 3a26454d0b7ed8d3bd15c1a1a356ba710e9eeae2..ccc7cce86883c89e1f49d671b7128284b413a2c7 100644 (file)
@@ -2138,6 +2138,45 @@ class UnixSysLogHandlerTest(SysLogHandlerTest):
         self.addCleanup(os_helper.unlink, self.address)
         SysLogHandlerTest.setUp(self)
 
+    def test_bytes_address(self):
+        # The Unix socket address can also be specified as bytes.
+        if self.server_exception:
+            self.skipTest(self.server_exception)
+        hdlr = logging.handlers.SysLogHandler(os.fsencode(self.address))
+        self.addCleanup(hdlr.close)
+        self.assertTrue(hdlr.unixsocket)
+        logger = logging.getLogger("slh-bytes")
+        logger.addHandler(hdlr)
+        self.addCleanup(logger.removeHandler, hdlr)
+        logger.error("sp\xe4m")
+        self.handled.wait(support.LONG_TIMEOUT)
+        self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
+
+@unittest.skipUnless(sys.platform in ('linux', 'android'),
+                     'Linux specific test')
+class AbstractNamespaceSysLogHandlerTest(BaseTest):
+
+    """Test for SysLogHandler with a socket in the abstract namespace."""
+
+    def check(self, address):
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+        self.addCleanup(sock.close)
+        sock.bind(address)
+        sock.settimeout(support.LONG_TIMEOUT)
+        hdlr = logging.handlers.SysLogHandler(address)
+        self.addCleanup(hdlr.close)
+        self.assertTrue(hdlr.unixsocket)
+        hdlr.emit(logging.makeLogRecord({'msg': 'sp\xe4m'}))
+        self.assertEqual(sock.recv(1024), b'<12>sp\xc3\xa4m\x00')
+
+    def test_str_address(self):
+        # A str address is encoded with the filesystem encoding.
+        self.check('\0' + os_helper.TESTFN)
+
+    def test_bytes_address(self):
+        # The name is an arbitrary byte sequence, it need not be decodable.
+        self.check(b'\0test_logging_%d_\xff\xfe' % os.getpid())
+
 @unittest.skipUnless(socket_helper.IPV6_ENABLED,
                      'IPv6 support required for this test.')
 class IPv6SysLogHandlerTest(SysLogHandlerTest):
diff --git a/Misc/NEWS.d/next/Library/2026-07-22-17-35-24.gh-issue-70990.xVHKwt.rst b/Misc/NEWS.d/next/Library/2026-07-22-17-35-24.gh-issue-70990.xVHKwt.rst
new file mode 100644 (file)
index 0000000..4af22f8
--- /dev/null
@@ -0,0 +1,4 @@
+:class:`logging.handlers.SysLogHandler` now accepts a :class:`bytes` address
+of a Unix domain socket, including an address in the abstract namespace.
+Previously only :class:`str` was recognized,
+and a :class:`bytes` address raised :exc:`ValueError`.