16
16
import queue
17
17
import subprocess
18
18
import threading
19
+ import time
19
20
from typing import List
20
21
21
22
@@ -43,6 +44,7 @@ class ProcessOutputCapture:
43
44
def __init__ (self , command : List [str ], output_path : str ):
44
45
# in/out/err are pipes
45
46
self .command = command
47
+ self .output_file = None # Output file handle
46
48
self .output_path = output_path
47
49
self .output_lines = queue .Queue ()
48
50
self .process = None
@@ -52,18 +54,13 @@ def __init__(self, command: List[str], output_path: str):
52
54
self .done = False
53
55
54
56
def _write_to_file (self , line : str , is_error_line = False ):
55
- """Writes a line to an output file in a thread-safe manner.
56
-
57
- Opens file in append-text mode ('at') with line buffering
58
- for immediate output to ensure all writes are appended.
59
- """
57
+ """Writes a line to an output file in a thread-safe manner."""
60
58
with self .lock :
61
- with open (self .output_path , "at" , buffering = 1 ) as f :
62
- if is_error_line :
63
- f .write (f"!!STDERR!! : { line } " )
64
- else :
65
- f .write (line )
66
- f .flush ()
59
+ if is_error_line :
60
+ self .output_file .write (f"!!STDERR!! : { line } " )
61
+ else :
62
+ self .output_file .write (line )
63
+ self .output_file .flush ()
67
64
68
65
def _stdout_thread (self ):
69
66
"""Reads stdout process lines and writes them to an output file.
@@ -103,6 +100,8 @@ def __enter__(self):
103
100
self .stderr_thread = threading .Thread (target = self ._stderr_thread )
104
101
self .stdout_thread .start ()
105
102
self .stderr_thread .start ()
103
+ self .output_file = open (self .output_path , "wt" , buffering = 1 ) # Enable line buffering
104
+ self ._write_to_file (f"### PROCESS START: { time .ctime ()} ###\n " )
106
105
return self
107
106
108
107
def __exit__ (self , exception_type , exception_value , traceback ):
@@ -117,6 +116,10 @@ def __exit__(self, exception_type, exception_value, traceback):
117
116
if self .stderr_thread :
118
117
self .stderr_thread .join ()
119
118
119
+ if self .output_file :
120
+ self ._write_to_file (f"### PROCESS END: { time .ctime ()} ###\n " )
121
+ self .output_file .close ()
122
+
120
123
if exception_value :
121
124
# When we fail because of an exception, report the entire log content
122
125
logging .error (f"-------- START: LOG DUMP FOR { self .command !r} -----" )
0 commit comments