You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多进程下Queue+WSGI+RotatingFileHandler写日志无输出问题

问题根因

日志无法写入文件由3个配置错误直接导致:

  • QueueListener 初始化参数要求传入已实例化的日志处理器对象,代码中传入的是配置内的处理器名称字符串,监听器无法识别字符串类型的处理器,完全无法执行日志输出逻辑
  • xyz 日志器同时绑定了WSGI流处理器、文件切分处理器和队列处理器,会导致日志重复输出;队列模式下日志输出全链路应为「业务代码→日志器→队列处理器→内存/跨进程队列→监听器线程→实际输出处理器」,日志器本身不应直接挂载实际输出处理器
  • 多进程场景下使用的queue.Queue是进程内内存队列,跨进程时数据不互通,子进程投递的日志无法到达主进程的监听器,自然不会写入文件
修复方案

核心调整逻辑

  1. 日志配置阶段不给业务logger直接挂载文件、WSGI流这类实际输出处理器,所有实际输出动作统一交给QueueListener调度
  2. 配置加载完成后,从logging全局管理器中取出已经实例化好的处理器对象,传入QueueListener,禁止直接传配置里的处理器名称字符串
  3. 多进程部署场景将内存队列替换为跨进程队列,保证不同worker进程的日志能正常投递到监听器
  4. 监听器必须在主进程启动,保证只有一个线程操作日志文件,从根源避免RotatingFileHandler多进程抢锁、切分异常的问题

可直接运行的修复后代码

import logging
import logging.config
import logging.handlers as handlers
from logging.handlers import QueueHandler, QueueListener
import queue
# 多进程部署时替换为跨进程队列
# from multiprocessing import Queue

config = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
    }},
    'handlers':{
        "fileHandler": {
            "class": "logging.handlers.RotatingFileHandler",
            "formatter": 'default',
            "filename": "testinglog.log",
            "maxBytes": 1024000,
            "backupCount": 5
        },
        'wsgi':{
            'class': 'logging.StreamHandler',
            'stream': 'ext://flask.logging.wsgi_errors_stream',
            'formatter': 'default'
        }
    },
    'loggers':{
        "xyz": {
            "handlers": [],
            "level": "INFO",
            'propagate': False,
        },
    }
}

# 加载日志配置
logging.config.dictConfig(config)

# 初始化队列:单进程用内存队列,多进程用跨进程队列
log_queue = queue.Queue(-1)
# log_queue = Queue(-1) # 多进程部署时启用该行

# 给业务logger挂载队列处理器
target_logger = logging.getLogger('xyz')
queue_handler = QueueHandler(log_queue)
target_logger.addHandler(queue_handler)

# 取出已实例化的实际输出处理器
file_handler = logging.getHandlerByName('fileHandler')
wsgi_handler = logging.getHandlerByName('wsgi')

# 启动队列监听器
listener = QueueListener(log_queue, file_handler, wsgi_handler, respect_handler_level=True)
listener.start()

# 业务侧日志测试
if __name__ == '__main__':
    target_logger.info("测试日志写入,该条日志会同时输出到WSGI错误流和本地日志文件")
额外注意事项
  • 程序退出前必须调用listener.stop(),将队列中残留的日志全部刷写到存储介质,避免日志丢失
  • 加上respect_handler_level=True参数,保证监听器会尊重每个处理器单独配置的日志级别,不会出现低级别日志被意外丢弃的问题
  • 队列模式下只有监听器线程会操作RotatingFileHandler,不存在多进程/多线程同时抢占文件句柄的问题,日志大小达到阈值时滚动切分可正常执行,不会出现文件损坏、切分失败的问题

内容的提问来源于stack exchange,提问作者dummy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:18:49