Skip to content

3.12.4 breakslogging.config.DictConfig with logging.handlers.QueueHandler on read-only file systems #120868

Closed
@provinzkraut

Description

@provinzkraut

Bug report

Bug description:

When using logging.config.dictConfig to configure a logging.handlers.QueueHandler on a read only file system, it works fine in 3.12.3, but crashes in 3.12.4.

Reproducing

# bug.py
import logging.config

logging.config.dictConfig(
    {
        "version": 1,
        "handlers": {
            "queue_listener": {
                "class": "logging.handlers.QueueHandler",
                "queue": {"()": "queue.Queue", "maxsize": -1},
            },
        },
    }
)
# Dockerfile
FROM python:3.12.4-slim-bookworm

COPY bug.py ./

CMD ["python", "bug.py"]

Run docker run --rm --read-only -it $(docker build -q .)

Process SyncManager-1:
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/usr/local/lib/python3.12/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 591, in _run_server
    server = cls._Server(registry, address, authkey, serializer)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 156, in __init__
    self.listener = Listener(address=address, backlog=128)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 458, in __init__
    address = address or arbitrary_address(family)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 77, in arbitrary_address
    return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir())
                                                   ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/util.py", line 149, in get_temp_dir
    tempdir = tempfile.mkdtemp(prefix='pymp-')
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/tempfile.py", line 373, in mkdtemp
    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/tempfile.py", line 126, in _sanitize_params
    dir = gettempdir()
          ^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/tempfile.py", line 315, in gettempdir
    return _os.fsdecode(_gettempdir())
                        ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/tempfile.py", line 308, in _gettempdir
    tempdir = _get_default_tempdir()
              ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/tempfile.py", line 223, in _get_default_tempdir
    raise FileNotFoundError(_errno.ENOENT,
FileNotFoundError: [Errno 2] No usable temporary directory found in ['/tmp', '/var/tmp', '/usr/tmp', '/']
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/logging/config.py", line 581, in configure
    handler = self.configure_handler(handlers[name])
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/logging/config.py", line 792, in configure_handler
    proxy_queue = MM().Queue()
                  ^^^^
  File "/usr/local/lib/python3.12/multiprocessing/context.py", line 57, in Manager
    m.start()
  File "/usr/local/lib/python3.12/multiprocessing/managers.py", line 566, in start
    self._address = reader.recv()
                    ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 250, in recv
    buf = self._recv_bytes()
          ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 430, in _recv_bytes
    buf = self._recv(4)
          ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/multiprocessing/connection.py", line 399, in _recv
    raise EOFError
EOFError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "//bug.py", line 3, in <module>
    logging.config.dictConfig(
  File "/usr/local/lib/python3.12/logging/config.py", line 920, in dictConfig
    dictConfigClass(config).configure()
  File "/usr/local/lib/python3.12/logging/config.py", line 588, in configure
    raise ValueError('Unable to configure handler '
ValueError: Unable to configure handler 'queue_listener'

From my understanding, this is related to #119819 et al. and the change that caused this was introduced in #120030: It introduces creating ephemeral instances of multiprocessing.Manager which, on init, tries to acquire a temporary directory.

proxy_queue = MM().Queue()

CPython versions tested on:

3.12

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions