issue #373: parse the child process wait status

Don't log the raw waitpid() result, convert it to a useful string first.
issue72
David Wilson 6 years ago
parent 48f9fc8930
commit 3aa5c4c53d

@ -93,6 +93,12 @@ SYS_EXECUTABLE_MSG = (
)
_sys_executable_warning_logged = False
SIGNAL_BY_NUM = dict(
(getattr(signal, name), name)
for name in sorted(vars(signal), reverse=True)
if name.startswith('SIG') and not name.startswith('SIG_')
)
def get_log_level():
return (LOG.level or logging.getLogger().level or logging.INFO)
@ -584,6 +590,21 @@ def _proxy_connect(name, method_name, kwargs, econtext):
}
def wstatus_to_str(status):
"""
Parse and format a :func:`os.waitpid` exit status.
"""
if os.WIFEXITED(status):
return 'exited with return code %d' % (os.WEXITSTATUS(status),)
if os.WIFSIGNALED(status):
n = os.WTERMSIG(status)
return 'exited due to signal %d (%s)' % (n, SIGNAL_BY_NUM.get(n))
if os.WIFSTOPPED(status):
n = os.WSTOPSIG(status)
return 'stopped due to signal %d (%s)' % (n, SIGNAL_BY_NUM.get(n))
return 'unknown wait status (%d)' % (status,)
class Argv(object):
"""
Wrapper to defer argv formatting when debug logging is disabled.
@ -961,7 +982,7 @@ class Stream(mitogen.core.Stream):
self._reaped = True
if pid:
LOG.debug('%r: child process exit status was %d', self, status)
LOG.debug('%r: PID %d %s', self, pid, wstatus_to_str(status))
return
# For processes like sudo we cannot actually send sudo a signal,

@ -1,5 +1,6 @@
import errno
import os
import signal
import subprocess
import sys
import tempfile
@ -44,6 +45,41 @@ class GetDefaultRemoteNameTest(testlib.TestCase):
self.assertEquals("ECORP_Administrator@box:123", self.func())
class WstatusToStrTest(testlib.TestCase):
func = staticmethod(mitogen.parent.wstatus_to_str)
def test_return_zero(self):
pid = os.fork()
if not pid:
os._exit(0)
(pid, status), _ = mitogen.core.io_op(os.waitpid, pid, 0)
self.assertEquals(self.func(status),
'exited with return code 0')
def test_return_one(self):
pid = os.fork()
if not pid:
os._exit(1)
(pid, status), _ = mitogen.core.io_op(os.waitpid, pid, 0)
self.assertEquals(
self.func(status),
'exited with return code 1'
)
def test_sigkill(self):
pid = os.fork()
if not pid:
time.sleep(600)
os.kill(pid, signal.SIGKILL)
(pid, status), _ = mitogen.core.io_op(os.waitpid, pid, 0)
self.assertEquals(
self.func(status),
'exited due to signal %s (SIGKILL)' % (signal.SIGKILL,)
)
# can't test SIGSTOP without POSIX sessions rabbithole
class ReapChildTest(testlib.RouterMixin, testlib.TestCase):
def test_connect_timeout(self):
# Ensure the child process is reaped if the connection times out.

Loading…
Cancel
Save