Python 的日志模块有啥进程不安全?

很早以前有一位老同事和我说 Python 日志模块多进程不安全,没办法多个进程同时写一个日志文件。当时只是看了一下 官方文档 确实明确的说是 Thread Safe,就也没有深究这个问题。

这几天正好看一个项目里用了 ConcurrentLogHandler 包,忽然想仔细看一下 Python 日志模块到底在多进程下有啥问题。

TL;DR;

  • 正常情况下,如果不做日志 Rotate,不会有任何问题
  • 如果多进程 Rotate 日志文件,会出问题
  • 这一切都和读写文件没什么关系

上面说的正常情况下,是指 Handle 初始化的时候模式要用默认的 mode='a'

1. 正常情况下,如果不做日志 Rotate,不会有任何问题

Python 的 logging.FileHandler 日志读写依赖的是什么?如果看过 logging.FileHandler日志模块的源码就知道该模块在初始化的时候会调用 open 打开一个文件输出流,每次写日志就是 write + flush 的过程。

def emit(self, record):
    try:
        msg = self.format(record)
        stream = self.stream
        stream.write(msg)
        stream.write(self.terminator)
        self.flush()
    except Exception:
        self.handleError(record)

而我们知道,python 在写文件的过程中,如果是通过 mode='a' 打开的文件,多进程写文件不会出现任何问题(见文末参考),所以,mode='a' 的情况下,多进程同时写日志文件不会出现任何问题

2. 如果多进程 Rotate 日志文件,会出问题

但是如果多个进程同时 Rotate 文件,就会出现问题。

一个典型的 case 是一个进程已经 Rotate 并写入 Rotate 后的文件了;
另一个进程此时恰巧进行 Rotate,就会删掉第一次创建的新文件,这期间第一个进程写入的日志就会丢失。

网上还有人说发现了特定情况下,同时写新旧两个日志文件的情况,这个我也没有遇到过,暂时也没有脑细胞分析会不会出现这种情况

3. 如何解决

相关的解决办法网上已经很多了,也不是本文讨论的重点,例如:

  • 重写 FileRotateHandler,目前我们线上程序就是沿着这个思路做的
  • 使用 ConcurrentLogHandler 包

备注:

A. ConcurrentLogHandler 的作用

我们可以看一下该模块官方文档是怎么说的:

Python logging handler that allows multiple processes to safely write to the same log file concurrently. This module extends the standard RotatingFileHandler functionality, and can be use as a drop-in replacement for that logging class.

Python 官方的 logging handler 允许多进程对日志文件的安全读写。本模块扩展了 RotatingFileHandler 的功能,可以用来直接替换原来的 RotatingFileHandler

B. 更多参考

  • Linux下多进程写同一文件,要不要加锁?
  • 多进程同时写一个文件会怎样?(待修订)
  • python多进程解决日志错乱问题
  • Python 多进程日志记录

你可能感兴趣的:(python)