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

如何避免Python多进程中子进程日志写入主进程日志文件?

解决子进程日志重复写入主日志文件的问题

问题根源是multiprocessing在fork子进程时,会完整复制主进程的内存空间,包括logging模块中已创建的Logger对象及其绑定的Handlers。你在子进程中重新调用create_logger时,获取的是同一个__name__对应的单例Logger,此时它已经继承了主进程添加的文件和控制台Handler,再加上子进程自己新增的Handler,就会导致日志同时输出到两个文件。

解决方法

在子进程初始化Logger时,先清空该Logger对象已有的所有Handlers,再添加子进程专属的Handler。直接修改create_logger函数即可实现:

import logging
import sys
import os
from pathlib import Path
import multiprocessing
import time


class ProcessFilter(logging.Filter):
    """仅接受来自特定pid的日志记录。"""

    def __init__(self, pid):
        self._pid = pid

    def filter(self, record):
        return record.process == self._pid


def create_logger(file):
    log = logging.getLogger(__name__)
    # 关键:清空已有Handler,避免继承主进程的Handler导致重复输出
    log.handlers.clear()
    log.setLevel(logging.DEBUG)
    log.addFilter(ProcessFilter(pid=os.getpid()))
    file_handler = logging.FileHandler(file)
    stream_handler = logging.StreamHandler(sys.stdout)
    formatter = logging.Formatter('[%(asctime)s] %(levelname)s [%(filename)s.%(funcName)s:%(lineno)d] %(message)s',
                                  datefmt='%a, %d %b %Y %H:%M:%S')
    file_handler.setFormatter(formatter)
    stream_handler.setFormatter(formatter)
    log.addHandler(file_handler)
    log.addHandler(stream_handler)
    return log


def subprocess_init():
    global log
    sub_log_file = str(Path.home()) + '/logfile_sub.log'
    log = create_logger(sub_log_file)
    do_subprocess_stuff()


def do_subprocess_stuff():
    count = 0
    while True:
        create_log("subprocess", count)
        time.sleep(5)
        count += 1


def main_tasks():
    num = 10
    while num > 0:
        create_log("main", num)
        time.sleep(5)
        num -= 1


def create_log(text, num):
    log.debug(text + " log %s", num)


if __name__ == '__main__':
    file = str(Path.home()) + '/logfile.log'
    log = create_logger(file)
    sub_process = multiprocessing.Process(target=subprocess_init, args=())
    sub_process.daemon = True
    sub_process.start()
    main_tasks()

额外说明

  • 如果你不需要在子进程中保留主进程的任何日志配置,log.handlers.clear()是最直接的方式,确保Logger只绑定当前进程的专属Handler。
  • 也可以在子进程初始化时单独清空Handler,再调用create_logger,但修改create_logger能让函数更健壮,无论在主进程还是子进程调用都不会出现重复Handler的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 09:33:20