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

如何用subprocess.check_output()实现子进程实时日志与自定义错误捕获?

问题分析

你当前的代码实现了main.py日志实时打印到控制台,但无法捕获其自定义错误信息,核心原因是:

  • 使用subprocess.check_output(..., stderr=sys.stderr)时,子进程的stderr被直接重定向到父进程的stderr(控制台),而非捕获到子进程的管道中,因此CalledProcessError的e.stderr属性为None,无法获取自定义错误内容。
优化方案

要同时满足实时打印日志和捕获自定义错误两个需求,需改用subprocess.Popen手动处理子进程的输出流,既实时打印到控制台,又将stderr内容保存用于错误返回。

修改后的app.py代码

import sys
import subprocess
from pathlib import Path
from flask import app

@app.route('/run_script', methods=['POST'])
def run_script_now():
    main_path = str(Path("main.py").resolve())
    error_output = []
    try:
        # 启动子进程,开启stdout/stderr管道,启用行缓冲实现实时输出
        with subprocess.Popen(
            ["python", main_path],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1,
            universal_newlines=True
        ) as proc:
            # 实时打印stdout到控制台
            for line in proc.stdout:
                print(line.rstrip(), file=sys.stdout)
                sys.stdout.flush()
            
            # 实时打印stderr到控制台,同时保存错误内容
            for line in proc.stderr:
                print(line.rstrip(), file=sys.stderr)
                sys.stderr.flush()
                error_output.append(line.rstrip())
            
            # 等待子进程结束,检查返回码
            returncode = proc.wait()
            if returncode != 0:
                # 手动抛出异常并传入捕获的stderr内容
                raise subprocess.CalledProcessError(
                    returncode, 
                    proc.args, 
                    stderr='\n'.join(error_output)
                )
        
        msg = ("Success", 200)
        logger.info(msg)
        return msg
    except subprocess.CalledProcessError as e:
        error_msg = f"Error: {e.stderr}"
        logger.critical(error_msg)
        return error_msg, 500

main.py补充优化

确保自定义错误信息能被正确输出,在sys.stderr.write后添加换行并刷新缓冲区:

try:
    portfolio_summary = processing.process_portfolio_summary()
except Exception as ex:
    error_msg = str(ex)
    sys_msg = f"Error en PortfolioSummary: {error_msg}"
    logger.error(sys_msg)
    # 添加换行+刷新缓冲区,避免内容滞留
    sys.stderr.write(f"{sys_msg}\n")
    sys.stderr.flush()
    sys.exit(1)
关键说明
  1. Popen替代check_output:允许手动控制输出流,兼顾实时打印和内容捕获。
  2. 行缓冲设置:bufsize=1确保子进程输出逐行刷新,实现实时日志效果。
  3. 双路处理stderr:既打印到控制台,又将每一行错误内容存入列表,最后拼接成完整错误信息传入异常。
  4. 手动抛出异常:子进程返回非0码时,主动构造CalledProcessError并传入捕获的stderr,保证e.stderr能拿到自定义错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:00:13