Skip to content
Open
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
6 changes: 5 additions & 1 deletion Doc/library/logging.handlers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,13 @@

.. 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 629 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
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
Expand Down Expand Up @@ -664,6 +665,9 @@
.. 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.
Expand Down
7 changes: 4 additions & 3 deletions Lib/logging/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,8 +886,9 @@ def __init__(self, address=('localhost', SYSLOG_UDP_PORT),
"""
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
Expand Down Expand Up @@ -938,7 +939,7 @@ def createSocket(self):
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.
Expand Down
39 changes: 39 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,45 @@ def setUp(self):
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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
Loading