Repository navigation
No way to capture stderr #11
Description
Problem
_run_stream captures stderr via subprocess.PIPE but never exposes it to the caller or subclasses. The captured process.stderr and process.returncode are silently discarded.
This makes it impossible to:
- Log diagnostic output from
TF_LOGduring streaming operations (plan, apply) - Detect and report errors that terraform/tofu writes to stderr
- Build subclasses that add logging or monitoring without fully reimplementing
_run_stream
In contrast, _run already returns a CommandResults dataclass that includes both stderr and returncode, so the pattern is established.
Proposed Solution
Store the process result on the instance after _run_stream executes, reusing the existing CommandResults dataclass. This is non-breaking — the generator API stays the same.
def _run_stream(self, args):
args = [self.binary_path] + [str(x) for x in args]
process = subprocess.run(
args,
cwd=self.cwd,
stdout=subprocess.PIPE,
capture_output=False,
stderr=subprocess.PIPE,
universal_newlines=True,
encoding="utf-8",
bufsize=1,
env={
**os.environ,
"TF_IN_AUTOMATION": "1",
"TF_LOG": self.log_level,
**self.env,
},
timeout=None,
)
# NEW: store result for callers/subclasses to inspect after iteration
self._last_stream_result = CommandResults(
command=" ".join(args),
stdout=process.stdout,
stderr=process.stderr,
returncode=process.returncode,
)
event_line = ""
for buffer in process.stdout:
if buffer == "\n":
yield json.loads(event_line)
event_line = ""
else:
event_line += bufferContext
We use tofupy in a Celery worker that runs terraform operations. Without stderr access, we have no visibility into terraform diagnostic output, which makes debugging production issues difficult.
P.S: TF_LOG_PATH env var: tofupy already supports passing env={"TF_LOG_PATH": "/tmp/terraform.log"} to redirect terraform logs to a file. This works but requires managing temp files and reading them after each operation, which is awkward in long-running workers that want to stream logs to Python's logging in real time. And it's for debug, it anyway doesn't capture the stderr...
Activity
uchime1234 commentedon Sep 15, 2026
Hi, I'd like to work on this. I'll implement the proposed solution — storing a CommandResults instance on self._last_stream_result after _run_stream finishes, mirroring what _run already does. I'll also add a test that verifies stderr and returncode are captured after streaming. Let me know if there's a preferred attribute name or if you'd rather expose it differently.
uchime1234 commentedon Sep 15, 2026
Opened a PR for this: #17