Skip to content

0.9.30

Choose a tag to compare

@Preston-Landers Preston-Landers released this 08 Oct 20:35
· 4 commits to master since this release
63d1566

What's Changed

  • 0.9.30

    • Mark Python 3.15 as supported.

    • Fix permission race window between file create and chmod, when the chmod and/or owner kwargs are configured.
      Issue #87

      The handler created files using the configured umask and applied _do_chown_and_chmod() afterward. In the
      window between create and chmod, the file was visible in the filesystem with umask-derived (potentially
      too-restrictive) permissions. A different-user process that opened the file during this window got
      PermissionError, breaking the cross-user log sharing scenario the chmod/owner kwargs exist to support.

      The lock file, the main log file, and rotated .gz files (from both handlers) are now pre-created atomically
      with the correct permissions: a hidden temp file gets the owner and mode, then os.link() (POSIX) or
      os.rename() (Windows) puts it in place. Other processes never see the public filename with intermediate
      perms. On filesystems without hard links (FAT/exFAT, many SMB/CIFS and FUSE mounts), the handler falls back to
      the previous create-then-chmod behavior. Handlers that don't configure chmod/owner are unaffected and pay
      no extra syscalls.

    • Fix lost records when a process opens a lock file or log file that another user owns, with chmod or owner
      configured. Only the owner of a file (or root) can chmod it, so every write from that process failed with
      PermissionError, even though the file was writable. The handler now skips chmod/chown when the file already
      has the configured mode and owner, and treats a failure as non-fatal (reported only in debug mode). Related
      to Issue #87.

    • ConcurrentTimedRotatingFileHandler no longer creates the log file in its constructor. The standard library
      created it there with the process umask, so the handler's umask, chmod, and owner settings did not apply
      until the first write. Until then, a process running as another user could fail to create its handler, with
      PermissionError. The file is now created on first write, as in ConcurrentRotatingFileHandler, and the
      delay argument is ignored.

    • ConcurrentTimedRotatingFileHandler now applies chmod and owner to rotated .gz files. Before, they kept
      umask-derived permissions.

    • Fix do_gzip() silently ignoring the configured umask parameter on rotated .gz files. The gzip.open()
      call previously ran outside the _alter_umask() context, so rotated archives picked up the process default
      umask instead of the handler's. Discovered while investigating Issue #87.

    • Fix a deadlock introduced in 0.9.29. If one thread was writing a log record when another thread called
      fork(), the child process hung on its first log call. The child now resets the handler's thread lock. In the
      same situation, a child that closed the handler before it logged (for example, through logging.shutdown()
      at exit) released the parent's file lock while the parent was still writing. The child now also clears the
      inherited lock state. Both fixes apply to Python 3.9 and later; on 3.7 and 3.8, logging holds handler locks
      across fork(), so these problems do not occur.

    • Fix loss of a rotated log file after a failed gzip (for example, disk full). The failure leaves the rotated
      file uncompressed. On the next rotation, ConcurrentRotatingFileHandler deleted that file (even when
      backupCount allowed more), and ConcurrentTimedRotatingFileHandler could overwrite it with a later file from
      the same period. Both handlers now keep it.

    • Remove a duplicate stale-file check from each write. On a local disk this cuts the time per write by about
      13% when maxBytes is set, for both handlers.

    Thanks to @jbfryar for a thorough bug report on Issue #87.

Full Changelog: 0.9.29...0.9.30