oeqa/qemurunner: Improve logging

Python unittest intercepts stdout and stderr however qemurunner sets
up a streamhandler before that interception occurs, hence the messages
spam the unittest output.

By moving the logging init to the class init time, we use the unittest
stdout/stderr and this means unittest can only show the log output upon
failure. This cleans up the selftest and testimage output whilst still
showing logging upon failure.

(From OE-Core rev: 9099cecc727fe0ae5f1559582426d30ba7a9f4d3)

(From OE-Core rev: ee13216284c4d49b762eaab488f21de573d2079d)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Richard Purdie 2017-09-07 10:49:19 +01:00
parent 8f35c388b4
commit 50750e1572
1 changed files with 45 additions and 45 deletions

View File

@ -17,11 +17,8 @@ import errno
import string import string
import threading import threading
import codecs import codecs
from oeqa.utils.dump import HostDumper
import logging import logging
logger = logging.getLogger("BitBake.QemuRunner") from oeqa.utils.dump import HostDumper
logger.addHandler(logging.StreamHandler())
# Get Unicode non printable control chars # Get Unicode non printable control chars
control_range = list(range(0,32))+list(range(127,160)) control_range = list(range(0,32))+list(range(127,160))
@ -58,6 +55,9 @@ class QemuRunner:
self.runqemutime = 120 self.runqemutime = 120
self.host_dumper = HostDumper(dump_host_cmds, dump_dir) self.host_dumper = HostDumper(dump_host_cmds, dump_dir)
self.logger = logging.getLogger("BitBake.QemuRunner")
self.logger.addHandler(logging.StreamHandler(sys.stdout))
def create_socket(self): def create_socket(self):
try: try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -65,7 +65,7 @@ class QemuRunner:
sock.bind(("127.0.0.1",0)) sock.bind(("127.0.0.1",0))
sock.listen(2) sock.listen(2)
port = sock.getsockname()[1] port = sock.getsockname()[1]
logger.info("Created listening socket for qemu serial console on: 127.0.0.1:%s" % port) self.logger.info("Created listening socket for qemu serial console on: 127.0.0.1:%s" % port)
return (sock, port) return (sock, port)
except socket.error: except socket.error:
@ -91,8 +91,8 @@ class QemuRunner:
def handleSIGCHLD(self, signum, frame): def handleSIGCHLD(self, signum, frame):
if self.runqemu and self.runqemu.poll(): if self.runqemu and self.runqemu.poll():
if self.runqemu.returncode: if self.runqemu.returncode:
logger.info('runqemu exited with code %d' % self.runqemu.returncode) self.logger.info('runqemu exited with code %d' % self.runqemu.returncode)
logger.info("Output from runqemu:\n%s" % self.getOutput(self.runqemu.stdout)) self.logger.info("Output from runqemu:\n%s" % self.getOutput(self.runqemu.stdout))
self.stop() self.stop()
self._dump_host() self._dump_host()
raise SystemExit raise SystemExit
@ -104,15 +104,15 @@ class QemuRunner:
# interact badly with screensavers. # interact badly with screensavers.
os.environ["QEMU_DONT_GRAB"] = "1" os.environ["QEMU_DONT_GRAB"] = "1"
if not os.path.exists(self.rootfs): if not os.path.exists(self.rootfs):
logger.error("Invalid rootfs %s" % self.rootfs) self.logger.error("Invalid rootfs %s" % self.rootfs)
return False return False
if not os.path.exists(self.tmpdir): if not os.path.exists(self.tmpdir):
logger.error("Invalid TMPDIR path %s" % self.tmpdir) self.logger.error("Invalid TMPDIR path %s" % self.tmpdir)
return False return False
else: else:
os.environ["OE_TMPDIR"] = self.tmpdir os.environ["OE_TMPDIR"] = self.tmpdir
if not os.path.exists(self.deploy_dir_image): if not os.path.exists(self.deploy_dir_image):
logger.error("Invalid DEPLOY_DIR_IMAGE path %s" % self.deploy_dir_image) self.logger.error("Invalid DEPLOY_DIR_IMAGE path %s" % self.deploy_dir_image)
return False return False
else: else:
os.environ["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image os.environ["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image
@ -120,10 +120,10 @@ class QemuRunner:
if not launch_cmd: if not launch_cmd:
launch_cmd = 'runqemu %s %s ' % ('snapshot' if discard_writes else '', runqemuparams) launch_cmd = 'runqemu %s %s ' % ('snapshot' if discard_writes else '', runqemuparams)
if self.use_kvm: if self.use_kvm:
logger.info('Using kvm for runqemu') self.logger.info('Using kvm for runqemu')
launch_cmd += ' kvm' launch_cmd += ' kvm'
else: else:
logger.info('Not using kvm for runqemu') self.logger.info('Not using kvm for runqemu')
if not self.display: if not self.display:
launch_cmd += ' nographic' launch_cmd += ' nographic'
launch_cmd += ' %s %s' % (self.machine, self.rootfs) launch_cmd += ' %s %s' % (self.machine, self.rootfs)
@ -135,7 +135,7 @@ class QemuRunner:
threadsock, threadport = self.create_socket() threadsock, threadport = self.create_socket()
self.server_socket, self.serverport = self.create_socket() self.server_socket, self.serverport = self.create_socket()
except socket.error as msg: except socket.error as msg:
logger.error("Failed to create listening socket: %s" % msg[1]) self.logger.error("Failed to create listening socket: %s" % msg[1])
return False return False
bootparams = 'console=tty1 console=ttyS0,115200n8 printk.time=1' bootparams = 'console=tty1 console=ttyS0,115200n8 printk.time=1'
@ -151,7 +151,7 @@ class QemuRunner:
self.origchldhandler = signal.getsignal(signal.SIGCHLD) self.origchldhandler = signal.getsignal(signal.SIGCHLD)
signal.signal(signal.SIGCHLD, self.handleSIGCHLD) signal.signal(signal.SIGCHLD, self.handleSIGCHLD)
logger.info('launchcmd=%s'%(launch_cmd)) self.logger.info('launchcmd=%s'%(launch_cmd))
# FIXME: We pass in stdin=subprocess.PIPE here to work around stty # FIXME: We pass in stdin=subprocess.PIPE here to work around stty
# blocking at the end of the runqemu script when using this within # blocking at the end of the runqemu script when using this within
@ -186,24 +186,24 @@ class QemuRunner:
os.killpg(os.getpgid(self.runqemu.pid), signal.SIGTERM) os.killpg(os.getpgid(self.runqemu.pid), signal.SIGTERM)
sys.exit(0) sys.exit(0)
logger.info("runqemu started, pid is %s" % self.runqemu.pid) self.logger.info("runqemu started, pid is %s" % self.runqemu.pid)
logger.info("waiting at most %s seconds for qemu pid" % self.runqemutime) self.logger.info("waiting at most %s seconds for qemu pid" % self.runqemutime)
endtime = time.time() + self.runqemutime endtime = time.time() + self.runqemutime
while not self.is_alive() and time.time() < endtime: while not self.is_alive() and time.time() < endtime:
if self.runqemu.poll(): if self.runqemu.poll():
if self.runqemu.returncode: if self.runqemu.returncode:
# No point waiting any longer # No point waiting any longer
logger.info('runqemu exited with code %d' % self.runqemu.returncode) self.logger.info('runqemu exited with code %d' % self.runqemu.returncode)
self._dump_host() self._dump_host()
self.stop() self.stop()
logger.info("Output from runqemu:\n%s" % self.getOutput(output)) self.logger.info("Output from runqemu:\n%s" % self.getOutput(output))
return False return False
time.sleep(1) time.sleep(1)
out = self.getOutput(output) out = self.getOutput(output)
netconf = False # network configuration is not required by default netconf = False # network configuration is not required by default
if self.is_alive(): if self.is_alive():
logger.info("qemu started in %s seconds - qemu procces pid is %s" % (time.time() - (endtime - self.runqemutime), self.qemupid)) self.logger.info("qemu started in %s seconds - qemu procces pid is %s" % (time.time() - (endtime - self.runqemutime), self.qemupid))
if get_ip: if get_ip:
cmdline = '' cmdline = ''
with open('/proc/%s/cmdline' % self.qemupid) as p: with open('/proc/%s/cmdline' % self.qemupid) as p:
@ -215,7 +215,7 @@ class QemuRunner:
ips = re.findall("((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1]) ips = re.findall("((?:[0-9]{1,3}\.){3}[0-9]{1,3})", cmdline.split("ip=")[1])
self.ip = ips[0] self.ip = ips[0]
self.server_ip = ips[1] self.server_ip = ips[1]
logger.info("qemu cmdline used:\n{}".format(cmdline)) self.logger.info("qemu cmdline used:\n{}".format(cmdline))
except (IndexError, ValueError): except (IndexError, ValueError):
# Try to get network configuration from runqemu output # Try to get network configuration from runqemu output
match = re.match('.*Network configuration: ([0-9.]+)::([0-9.]+):([0-9.]+)$.*', match = re.match('.*Network configuration: ([0-9.]+)::([0-9.]+):([0-9.]+)$.*',
@ -227,27 +227,27 @@ class QemuRunner:
# and guest networking is not configured # and guest networking is not configured
netconf = True netconf = True
else: else:
logger.error("Couldn't get ip from qemu command line and runqemu output! " self.logger.error("Couldn't get ip from qemu command line and runqemu output! "
"Here is the qemu command line used:\n%s\n" "Here is the qemu command line used:\n%s\n"
"and output from runqemu:\n%s" % (cmdline, out)) "and output from runqemu:\n%s" % (cmdline, out))
self._dump_host() self._dump_host()
self.stop() self.stop()
return False return False
logger.info("Target IP: %s" % self.ip) self.logger.info("Target IP: %s" % self.ip)
logger.info("Server IP: %s" % self.server_ip) self.logger.info("Server IP: %s" % self.server_ip)
self.thread = LoggingThread(self.log, threadsock, logger) self.thread = LoggingThread(self.log, threadsock, self.logger)
self.thread.start() self.thread.start()
if not self.thread.connection_established.wait(self.boottime): if not self.thread.connection_established.wait(self.boottime):
logger.error("Didn't receive a console connection from qemu. " self.logger.error("Didn't receive a console connection from qemu. "
"Here is the qemu command line used:\n%s\nand " "Here is the qemu command line used:\n%s\nand "
"output from runqemu:\n%s" % (cmdline, out)) "output from runqemu:\n%s" % (cmdline, out))
self.stop_thread() self.stop_thread()
return False return False
logger.info("Output from runqemu:\n%s", out) self.logger.info("Output from runqemu:\n%s", out)
logger.info("Waiting at most %d seconds for login banner" % self.boottime) self.logger.info("Waiting at most %d seconds for login banner" % self.boottime)
endtime = time.time() + self.boottime endtime = time.time() + self.boottime
socklist = [self.server_socket] socklist = [self.server_socket]
reachedlogin = False reachedlogin = False
@ -266,7 +266,7 @@ class QemuRunner:
qemusock.setblocking(0) qemusock.setblocking(0)
socklist.append(qemusock) socklist.append(qemusock)
socklist.remove(self.server_socket) socklist.remove(self.server_socket)
logger.info("Connection from %s:%s" % addr) self.logger.info("Connection from %s:%s" % addr)
else: else:
data = data + sock.recv(1024) data = data + sock.recv(1024)
if data: if data:
@ -278,7 +278,7 @@ class QemuRunner:
self.server_socket = qemusock self.server_socket = qemusock
stopread = True stopread = True
reachedlogin = True reachedlogin = True
logger.info("Reached login banner") self.logger.info("Reached login banner")
except UnicodeDecodeError: except UnicodeDecodeError:
continue continue
else: else:
@ -287,10 +287,10 @@ class QemuRunner:
stopread = True stopread = True
if not reachedlogin: if not reachedlogin:
logger.info("Target didn't reached login boot in %d seconds" % self.boottime) self.logger.info("Target didn't reached login boot in %d seconds" % self.boottime)
lines = "\n".join(bootlog.splitlines()[-25:]) lines = "\n".join(bootlog.splitlines()[-25:])
logger.info("Last 25 lines of text:\n%s" % lines) self.logger.info("Last 25 lines of text:\n%s" % lines)
logger.info("Check full boot log: %s" % self.logfile) self.logger.info("Check full boot log: %s" % self.logfile)
self._dump_host() self._dump_host()
self.stop() self.stop()
return False return False
@ -300,30 +300,30 @@ class QemuRunner:
(status, output) = self.run_serial("root\n", raw=True) (status, output) = self.run_serial("root\n", raw=True)
if re.search("root@[a-zA-Z0-9\-]+:~#", output): if re.search("root@[a-zA-Z0-9\-]+:~#", output):
self.logged = True self.logged = True
logger.info("Logged as root in serial console") self.logger.info("Logged as root in serial console")
if netconf: if netconf:
# configure guest networking # configure guest networking
cmd = "ifconfig eth0 %s netmask %s up\n" % (self.ip, self.netmask) cmd = "ifconfig eth0 %s netmask %s up\n" % (self.ip, self.netmask)
output = self.run_serial(cmd, raw=True)[1] output = self.run_serial(cmd, raw=True)[1]
if re.search("root@[a-zA-Z0-9\-]+:~#", output): if re.search("root@[a-zA-Z0-9\-]+:~#", output):
logger.info("configured ip address %s", self.ip) self.logger.info("configured ip address %s", self.ip)
else: else:
logger.info("Couldn't configure guest networking") self.logger.info("Couldn't configure guest networking")
else: else:
logger.info("Couldn't login into serial console" self.logger.info("Couldn't login into serial console"
" as root using blank password") " as root using blank password")
except: except:
logger.info("Serial console failed while trying to login") self.logger.info("Serial console failed while trying to login")
else: else:
logger.error("Qemu pid didn't appear in %s seconds" % self.runqemutime) self.logger.error("Qemu pid didn't appear in %s seconds" % self.runqemutime)
self._dump_host() self._dump_host()
self.stop() self.stop()
op = self.getOutput(output) op = self.getOutput(output)
if op: if op:
logger.error("Output from runqemu:\n%s" % op) self.logger.error("Output from runqemu:\n%s" % op)
else: else:
logger.error("No output from runqemu.\n") self.logger.error("No output from runqemu.\n")
return False return False
return self.is_alive() return self.is_alive()
@ -336,7 +336,7 @@ class QemuRunner:
if self.runqemu: if self.runqemu:
if hasattr(self, "monitorpid"): if hasattr(self, "monitorpid"):
os.kill(self.monitorpid, signal.SIGKILL) os.kill(self.monitorpid, signal.SIGKILL)
logger.info("Sending SIGTERM to runqemu") self.logger.info("Sending SIGTERM to runqemu")
try: try:
os.killpg(os.getpgid(self.runqemu.pid), signal.SIGTERM) os.killpg(os.getpgid(self.runqemu.pid), signal.SIGTERM)
except OSError as e: except OSError as e:
@ -346,7 +346,7 @@ class QemuRunner:
while self.runqemu.poll() is None and time.time() < endtime: while self.runqemu.poll() is None and time.time() < endtime:
time.sleep(1) time.sleep(1)
if self.runqemu.poll() is None: if self.runqemu.poll() is None:
logger.info("Sending SIGKILL to runqemu") self.logger.info("Sending SIGKILL to runqemu")
os.killpg(os.getpgid(self.runqemu.pid), signal.SIGKILL) os.killpg(os.getpgid(self.runqemu.pid), signal.SIGKILL)
self.runqemu = None self.runqemu = None
if hasattr(self, 'server_socket') and self.server_socket: if hasattr(self, 'server_socket') and self.server_socket:
@ -361,7 +361,7 @@ class QemuRunner:
# qemu-system behaves well and a SIGTERM is enough # qemu-system behaves well and a SIGTERM is enough
os.kill(self.qemupid, signal.SIGTERM) os.kill(self.qemupid, signal.SIGTERM)
except ProcessLookupError as e: except ProcessLookupError as e:
logger.warn('qemu-system ended unexpectedly') self.logger.warn('qemu-system ended unexpectedly')
def stop_thread(self): def stop_thread(self):
if self.thread and self.thread.is_alive(): if self.thread and self.thread.is_alive():
@ -369,7 +369,7 @@ class QemuRunner:
self.thread.join() self.thread.join()
def restart(self, qemuparams = None): def restart(self, qemuparams = None):
logger.info("Restarting qemu process") self.logger.info("Restarting qemu process")
if self.runqemu.poll() is None: if self.runqemu.poll() is None:
self.stop() self.stop()
if self.start(qemuparams): if self.start(qemuparams):
@ -478,7 +478,7 @@ class QemuRunner:
def _dump_host(self): def _dump_host(self):
self.host_dumper.create_dir("qemu") self.host_dumper.create_dir("qemu")
logger.warn("Qemu ended unexpectedly, dump data from host" self.logger.warn("Qemu ended unexpectedly, dump data from host"
" is in %s" % self.host_dumper.dump_dir) " is in %s" % self.host_dumper.dump_dir)
self.host_dumper.dump_host() self.host_dumper.dump_host()