1414import signal
1515import subprocess
1616import sys
17+ import tempfile
1718import time
1819from pathlib import Path
1920
@@ -46,6 +47,7 @@ class E2ETestRunnerBase:
4647 def __init__ (self , app_port : int = 8000 ):
4748 self .app_port = app_port
4849 self .app_process : subprocess .Popen | None = None
50+ self .app_log_file : tempfile ._TemporaryFileWrapper | None = None
4951 self .exit_code = 0
5052 self .expected_request_count : int | None = None
5153
@@ -149,11 +151,17 @@ def record_traces(self) -> bool:
149151 self .log ("Starting application in RECORD mode..." , Colors .GREEN )
150152 env = {"TUSK_DRIFT_MODE" : "RECORD" , "PYTHONUNBUFFERED" : "1" }
151153
154+ # Use a temporary file to capture app output for debugging.
155+ # This avoids pipe buffer issues while still allowing diagnostics.
156+ # Note: Can't use context manager here - file must stay open for subprocess
157+ # and be cleaned up later in cleanup(). Using delete=False + manual unlink.
158+ self .app_log_file = tempfile .NamedTemporaryFile (mode = "w+" , suffix = ".log" , delete = False ) # noqa: SIM115
159+
152160 self .app_process = subprocess .Popen (
153161 ["python" , "src/app.py" ],
154162 env = {** os .environ , ** env },
155- stdout = subprocess . DEVNULL ,
156- stderr = subprocess .DEVNULL ,
163+ stdout = self . app_log_file ,
164+ stderr = subprocess .STDOUT ,
157165 text = True ,
158166 )
159167
@@ -168,10 +176,18 @@ def record_traces(self) -> bool:
168176 except TimeoutError :
169177 self .log ("Application failed to become ready" , Colors .RED )
170178 if self .app_process :
171- # Print app output for debugging
172179 self .app_process .terminate ()
173- stdout , _ = self .app_process .communicate (timeout = 5 )
174- self .log (f"App output: { stdout } " , Colors .YELLOW )
180+ try :
181+ self .app_process .wait (timeout = 5 )
182+ except subprocess .TimeoutExpired :
183+ self .app_process .kill ()
184+ self .app_process .wait ()
185+ # Read and display app output for debugging
186+ if self .app_log_file :
187+ self .app_log_file .flush ()
188+ self .app_log_file .seek (0 )
189+ app_output = self .app_log_file .read ()
190+ self .log (f"App output:\n { app_output } " , Colors .YELLOW )
175191 self .exit_code = 1
176192 return False
177193
@@ -387,6 +403,15 @@ def cleanup(self):
387403 self .app_process .kill ()
388404 self .app_process .wait ()
389405
406+ # Clean up app log file
407+ if self .app_log_file :
408+ try :
409+ self .app_log_file .close ()
410+ os .unlink (self .app_log_file .name )
411+ except OSError :
412+ pass
413+ self .app_log_file = None
414+
390415 # Traces are kept in container for inspection
391416 self .log ("Cleanup complete" , Colors .GREEN )
392417
0 commit comments