Skip to content

Commit 32575a8

Browse files
authored
Stderr is now by default UTF-8 (#624)
* Stderr is now by default UTF-8 * Stderr check for None * encapsulated UTF-8 reading and watched for async access * Empty * stderr is always string, so we can remove None check * Refactoring
1 parent a8b500d commit 32575a8

File tree

3 files changed

+19
-7
lines changed

3 files changed

+19
-7
lines changed

metric_providers/base.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,18 @@ def check_system(self):
5050

5151
# implemented as getter function and not direct access, so it can be overloaded
5252
# some child classes might not actually have _ps attribute set
53+
#
54+
# This function has to go through quite some hoops to read the stderr
55+
# The preferred way to communicate with processes is through communicate()
56+
# However this function ALWAYS waits for the process to terminate and it does not allow reading from processes
57+
# in chunks while they are running. Thus we we cannot set encoding='UTF-8' in Popen and must decode here.
5358
def get_stderr(self):
54-
return self._ps.stderr.read()
59+
stderr_read = ''
60+
if self._ps.stderr is not None:
61+
stderr_read = self._ps.stderr.read()
62+
if isinstance(stderr_read, bytes):
63+
stderr_read = stderr_read.decode('utf-8')
64+
return stderr_read
5565

5666
def has_started(self):
5767
return self._has_started
@@ -131,7 +141,9 @@ def start_profiling(self, containers=None):
131141
[call_string],
132142
shell=True,
133143
preexec_fn=os.setsid,
134-
stderr=subprocess.PIPE
144+
stderr=subprocess.PIPE,
145+
#encoding='UTF-8' # we cannot set this option here as reading later will then flake with "can't concat NoneType to bytes"
146+
# see get_stderr() for additional details
135147
# since we are launching the command with shell=True we cannot use ps.terminate() / ps.kill().
136148
# This would just kill the executing shell, but not it's child and make the process an orphan.
137149
# therefore we use os.setsid here and later call os.getpgid(pid) to get process group that the shell

metric_providers/powermetrics/provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def read_metrics(self, run_id, containers=None):
181181
def get_stderr(self):
182182
stderr = super().get_stderr()
183183

184-
if stderr is not None and str(stderr).find('proc_pid') != -1:
184+
if stderr.find('proc_pid') != -1:
185185
return None
186186

187187
return stderr

runner.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ def start_metric_providers(self, allow_container=True, allow_other=True):
966966

967967
stderr_read = metric_provider.get_stderr()
968968
print(f"Stderr check on {metric_provider.__class__.__name__}")
969-
if stderr_read is not None and str(stderr_read):
969+
if stderr_read:
970970
raise RuntimeError(f"Stderr on {metric_provider.__class__.__name__} was NOT empty: {stderr_read}")
971971

972972

@@ -1100,7 +1100,7 @@ def stop_metric_providers(self):
11001100
continue
11011101

11021102
stderr_read = metric_provider.get_stderr()
1103-
if stderr_read is not None and str(stderr_read):
1103+
if stderr_read:
11041104
errors.append(f"Stderr on {metric_provider.__class__.__name__} was NOT empty: {stderr_read}")
11051105

11061106
# pylint: disable=broad-exception-caught
@@ -1141,6 +1141,7 @@ def read_and_cleanup_processes(self):
11411141

11421142
for ps in self.__ps_to_read:
11431143
if ps['detach']:
1144+
# communicate will only really work to our experience if the process is killed before
11441145
stdout, stderr = ps['ps'].communicate(timeout=5)
11451146
else:
11461147
stdout = ps['ps'].stdout
@@ -1159,8 +1160,7 @@ def read_and_cleanup_processes(self):
11591160
if match := re.findall(r'GMT_SCI_R=(\d+)', line):
11601161
self._sci['R'] += int(match[0])
11611162
if stderr:
1162-
stderr = stderr.splitlines()
1163-
for line in stderr:
1163+
for line in stderr.splitlines():
11641164
print('stderr from process:', ps['cmd'], line)
11651165
self.add_to_log(ps['container_name'], f"stderr: {line}", ps['cmd'])
11661166

0 commit comments

Comments
 (0)