Python的logging库为啥设计成不支持多进程?

而且 django 为何默认使用 logging 记录日志,难道 django 都是部署单进程的吗?


Python的logging库为啥设计成不支持多进程?
5 回复

这其实是个常见的误解。Python的logging库本身是支持多进程的,只是默认的FileHandler在多进程写入同一个日志文件时会有问题。

核心原因是:多个进程同时写入同一个文件时,操作系统层面的文件句柄和写入位置管理会导致日志内容错乱、覆盖或丢失。这不是logging库的设计缺陷,而是并发文件写入的通用挑战。

要解决这个问题,有几种标准做法:

  1. 使用ConcurrentLogHandlerlogging.handlers.QueueHandler(Python 3.2+) 这是官方推荐的方式。主进程设置日志处理器,子进程通过队列发送日志消息:
import logging
import logging.handlers
from multiprocessing import Process, Queue
import time

def worker_process(queue):
    handler = logging.handlers.QueueHandler(queue)
    logger = logging.getLogger()
    logger.addHandler(handler)
    logger.setLevel(logging.INFO)
    
    # 这些日志消息会被发送到队列
    logger.info('Worker process started')
    logger.error('An error occurred')

def listener_process(queue):
    while True:
        try:
            record = queue.get()
            if record is None:  # 终止信号
                break
            logger = logging.getLogger(record.name)
            logger.handle(record)
        except Exception:
            import sys, traceback
            print('Problem in listener:', file=sys.stderr)
            traceback.print_exc(file=sys.stderr)

if __name__ == '__main__':
    queue = Queue()
    
    # 设置主进程的日志处理器(实际写入文件)
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(processName)s - %(message)s',
        filename='app.log'
    )
    
    # 启动监听进程
    listener = Process(target=listener_process, args=(queue,))
    listener.start()
    
    # 启动工作进程
    workers = []
    for i in range(3):
        worker = Process(target=worker_process, args=(queue,))
        workers.append(worker)
        worker.start()
    
    # 等待工作进程结束
    for w in workers:
        w.join()
    
    # 发送终止信号给监听进程
    queue.put(None)
    listener.join()
  1. 使用第三方库如concurrent-log-handler 它提供了带锁的ConcurrentRotatingFileHandler
from concurrent_log_handler import ConcurrentRotatingFileHandler

handler = ConcurrentRotatingFileHandler(
    'app.log', 
    maxBytes=1024*1024, 
    backupCount=5
)
logging.getLogger().addHandler(handler)
  1. 每个进程写不同的日志文件 最简单的方案,但后期日志整合麻烦。

  2. 使用系统日志服务(如syslog) 适合Linux/Unix环境。

所以准确来说,logging库是支持多进程的,只是需要选择合适的处理器来避免文件写入冲突。对于生产环境,推荐使用QueueHandler方案,这是最稳定可靠的方式。

总结:用QueueHandler解决多进程日志问题。

可以用 logging 接口来自定义 log 服务啊,还可以用队列来异步化。

可以配置不同得日志文件

回到顶部