如何获取subprocess启动的Python进程的logging日志并同步输出到控制台
解决方案
核心问题原因
操作系统的进程隔离机制决定了主进程和子进程拥有完全独立的内存地址空间,你当前实现的LogWrapper将日志存储在子进程自身的内存队列中,主进程无法直接跨进程读取该队列的运行时内容,只能拿到初始化阶段的少量残留数据,这是方案失效的根本原因。
方案1:管道重定向(最简便)
直接通过subprocess的管道能力捕获子进程的stdout/stderr输出,无需改造子进程的日志核心逻辑,适配成本最低。
主进程实现步骤
- 启动子进程时指定stdout、stderr参数开启管道,合并标准输出和标准错误,开启行缓冲避免日志攒批:
import subprocess import logging import threading # 提前配置主进程全局logging格式 logging.basicConfig( level=logging.DEBUG, format="%(asctime)s | %(levelname)s | %(message)s" ) main_logger = logging.getLogger(__name__) # 启动子进程 sub_proc = subprocess.Popen( ["python", "你的pygame子窗口脚本路径.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 把错误输出合并到标准输出,无需分开处理 text=True, bufsize=1 # 行缓冲,日志实时输出 )
- 开启独立守护线程实时读取管道内容,输出到主进程日志:
def capture_sub_log(proc, logger): for line in proc.stdout: stripped_line = line.strip() if stripped_line: # 可自定义前缀区分子进程日志,也可以解析日志内容匹配主进程的日志级别 logger.info(f"[子窗口进程] {stripped_line}") # 启动日志捕获线程,设为守护线程跟随主进程自动退出 threading.Thread( target=capture_sub_log, args=(sub_proc, main_logger), daemon=True ).start()
子进程适配
只需在子进程脚本开头配置logging输出到stdout即可,原有打日志的代码无需修改:
import logging # 子进程logging配置,输出到默认stdout logging.basicConfig( level=logging.DEBUG, format="%(levelname)s | %(module)s | %(message)s" ) # 后续正常调用logging.debug/info/error即可,日志会自动被主进程捕获
方案2:socket通道复用(适合已有socket通信的场景)
如果你已经实现了主进程和子进程的本地socket通信,可以直接复用该通道传输日志,无需额外开启管道,逻辑更统一。
子进程实现自定义日志Handler
import logging # 假设你已经在子进程中初始化了连接主进程的socket对象:sub_socket class SocketLogHandler(logging.Handler): def emit(self, record): log_content = self.format(record) # 加特殊前缀和普通业务消息做区分 send_msg = f"[LOG]{log_content}".encode("utf-8") sub_socket.sendall(send_msg) # 给子进程全局logger添加自定义handler sub_logger = logging.getLogger() sub_logger.addHandler(SocketLogHandler())
主进程适配
在原有socket消息接收逻辑中增加判断,收到带[LOG]前缀的消息时直接输出到主进程日志,其余消息走原有业务处理逻辑即可。
内容的提问来源于stack exchange,提问作者Yes
相关产品推荐
相关产品推荐

