调用subprocess执行脚本时,logging输出与异常捕获问题求助
问题解决指南
问题1:logging输出全部流入stderr
原因
Python的logging模块默认使用StreamHandler,且默认指向sys.stderr,所有级别(INFO、WARNING、ERROR)的日志都会输出到stderr。
解决方案
在b.py中配置两个日志处理器,分别将不同级别的日志导向stdout和stderr:
import logging import sys # 处理INFO和WARNING级别的日志,输出到stdout stdout_handler = logging.StreamHandler(sys.stdout) stdout_handler.setLevel(logging.INFO) # 过滤掉ERROR及以上级别的日志 stdout_handler.addFilter(lambda record: record.levelno < logging.ERROR) # 处理ERROR及以上级别的日志,输出到stderr stderr_handler = logging.StreamHandler(sys.stderr) stderr_handler.setLevel(logging.ERROR) # 配置根logger root_logger = logging.getLogger() root_logger.setLevel(logging.INFO) # 确保INFO及以上级别被捕获 root_logger.addHandler(stdout_handler) root_logger.addHandler(stderr_handler)
问题2:a.py无法捕获b.py的执行错误
原因
subprocess.Popen和communicate()仅在启动子进程失败时(比如找不到Python解释器、b.py不存在)才会抛出异常。如果b.py运行过程中出错(比如代码抛出异常),子进程只会返回非零的返回码,不会触发a.py的except块。
解决方案
方案1:检查返回码手动抛出异常
修改a.py的代码,在communicate()后检查子进程的返回码,非零则手动触发异常:
import subprocess as sp import json # 假设user_conf已定义 user_conf = {"key": "value"} try: p = sp.Popen( ["python", "b.py", "--user_config", json.dumps(user_conf)], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, encoding='cp1252' ) stdout, stderr = p.communicate() # 检查返回码,非零表示子进程执行出错 if p.returncode != 0: raise RuntimeError(f"b.py执行失败,返回码:{p.returncode},错误信息:{stderr}") except Exception as e: print(e) else: print("Script continues...")
方案2:使用subprocess.run简化处理
subprocess.run支持check=True参数,当子进程返回非零码时自动抛出CalledProcessError异常,代码更简洁:
import subprocess as sp import json user_conf = {"key": "value"} try: result = sp.run( ["python", "b.py", "--user_config", json.dumps(user_conf)], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, encoding='cp1252', check=True ) # 正常执行时获取输出 print("b.py stdout:", result.stdout) except sp.CalledProcessError as e: print(f"b.py执行出错:{e.stderr}") except Exception as e: print(e) else: print("Script continues...")
内容的提问来源于stack exchange,提问作者Maheswarha Rajagopal
相关产品推荐
相关产品推荐

