bitbake: toasterui: refactor log saving and save out-of-build errors

We refactor log saving to go through only one code path.

All logs that happened outside the build (i.e. before build
starting) now will be logged to either toaster_ui.log if the
build command ran in interactive mode, or to the build request
errors if the command ran in managed mode.

This enables proper display of error logs in project page.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Alexandru DAMIAN 2014-07-24 18:20:25 +01:00 committed by Richard Purdie
parent 669c07d602
commit 7eb3e45a33
2 changed files with 51 additions and 38 deletions

View File

@ -480,6 +480,8 @@ class ORMWrapper(object):
line_number = vh['line'], line_number = vh['line'],
operation = vh['op']) operation = vh['op'])
class MockEvent: pass # sometimes we mock an event, declare it here
class BuildInfoHelper(object): class BuildInfoHelper(object):
""" This class gathers the build information from the server and sends it """ This class gathers the build information from the server and sends it
towards the ORM wrapper for storing in the database towards the ORM wrapper for storing in the database
@ -487,6 +489,7 @@ class BuildInfoHelper(object):
Keeps in memory all data that needs matching before writing it to the database Keeps in memory all data that needs matching before writing it to the database
""" """
def __init__(self, server, has_build_history = False): def __init__(self, server, has_build_history = False):
self._configure_django() self._configure_django()
self.internal_state = {} self.internal_state = {}
@ -496,6 +499,8 @@ class BuildInfoHelper(object):
self.orm_wrapper = ORMWrapper() self.orm_wrapper = ORMWrapper()
self.has_build_history = has_build_history self.has_build_history = has_build_history
self.tmp_dir = self.server.runCommand(["getVariable", "TMPDIR"])[0] self.tmp_dir = self.server.runCommand(["getVariable", "TMPDIR"])[0]
self.brbe = self.server.runCommand(["getVariable", "TOASTER_BRBE"])[0]
def _configure_django(self): def _configure_django(self):
# Add toaster to sys path for importing modules # Add toaster to sys path for importing modules
@ -607,9 +612,7 @@ class BuildInfoHelper(object):
assert '_pkgs' in vars(event) assert '_pkgs' in vars(event)
build_information = self._get_build_information() build_information = self._get_build_information()
brbe = self.server.runCommand(["getVariable", "TOASTER_BRBE"])[0] build_obj = self.orm_wrapper.create_build_object(build_information, self.brbe)
build_obj = self.orm_wrapper.create_build_object(build_information, brbe)
self.internal_state['build'] = build_obj self.internal_state['build'] = build_obj
@ -629,7 +632,8 @@ class BuildInfoHelper(object):
# Save build configuration # Save build configuration
self.orm_wrapper.save_build_variables(build_obj, self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0]) self.orm_wrapper.save_build_variables(build_obj, self.server.runCommand(["getAllKeysWithFlags", ["doc", "func"]])[0])
return brbe return self.brbe
def update_target_image_file(self, event): def update_target_image_file(self, event):
@ -773,7 +777,6 @@ class BuildInfoHelper(object):
identifier = fn + taskname + "_setscene" identifier = fn + taskname + "_setscene"
recipe_information = self._get_recipe_information_from_taskfile(fn) recipe_information = self._get_recipe_information_from_taskfile(fn)
recipe = self.orm_wrapper.get_update_recipe_object(recipe_information) recipe = self.orm_wrapper.get_update_recipe_object(recipe_information)
class MockEvent: pass
mevent = MockEvent() mevent = MockEvent()
mevent.taskname = taskname mevent.taskname = taskname
mevent.taskhash = taskhash mevent.taskhash = taskhash
@ -792,7 +795,6 @@ class BuildInfoHelper(object):
identifier = fn + taskname + "_setscene" identifier = fn + taskname + "_setscene"
recipe_information = self._get_recipe_information_from_taskfile(fn) recipe_information = self._get_recipe_information_from_taskfile(fn)
recipe = self.orm_wrapper.get_update_recipe_object(recipe_information) recipe = self.orm_wrapper.get_update_recipe_object(recipe_information)
class MockEvent: pass
mevent = MockEvent() mevent = MockEvent()
mevent.taskname = taskname mevent.taskname = taskname
mevent.taskhash = taskhash mevent.taskhash = taskhash
@ -929,7 +931,8 @@ class BuildInfoHelper(object):
self.internal_state['recipes'], self.internal_state['recipes'],
) )
def store_build_done(self, br_id, be_id): def _store_build_done(self):
br_id, be_id = self.brbe.split(":")
from bldcontrol.models import BuildEnvironment, BuildRequest from bldcontrol.models import BuildEnvironment, BuildRequest
be = BuildEnvironment.objects.get(pk = be_id) be = BuildEnvironment.objects.get(pk = be_id)
be.lock = BuildEnvironment.LOCK_LOCK be.lock = BuildEnvironment.LOCK_LOCK
@ -939,49 +942,61 @@ class BuildInfoHelper(object):
br.build = self.internal_state['build'] br.build = self.internal_state['build']
br.save() br.save()
def _store_log_information(self, level, text):
log_information = {}
log_information['build'] = self.internal_state['build']
log_information['level'] = level
log_information['message'] = text
self.orm_wrapper.create_logmessage(log_information)
def store_log_info(self, text):
self._store_log_information(LogMessage.INFO, text)
def store_log_warn(self, text):
self._store_log_information(LogMessage.WARNING, text)
def store_log_error(self, text): def store_log_error(self, text):
self._store_log_information(LogMessage.ERROR, text) mockevent = MockEvent()
mockevent.levelno = format.ERROR
mockevent.msg = text
self.store_log_event(mockevent)
def store_log_event(self, event): def store_log_event(self, event):
if event.levelno < format.WARNING:
return
if 'args' in vars(event):
event.msg = event.msg % event.args
if not 'build' in self.internal_state:
if self.brbe is None:
if not 'backlog' in self.internal_state:
self.internal_state['backlog'] = []
self.internal_state['backlog'].append(event)
else: # we're under Toaster control, post the errors to the build request
from bldcontrol.models import BuildRequest, BRError
br, be = brbe.split(":")
buildrequest = BuildRequest.objects.get(pk = br)
brerror = BRError.objects.create(req = buildrequest, errtype="build", errmsg = event.msg)
return
if 'build' in self.internal_state and 'backlog' in self.internal_state: if 'build' in self.internal_state and 'backlog' in self.internal_state:
if len(self.internal_state['backlog']): if len(self.internal_state['backlog']):
tempevent = self.internal_state['backlog'].pop() tempevent = self.internal_state['backlog'].pop()
print "Saving stored event ", tempevent print " Saving stored event ", tempevent
self.store_log_event(tempevent) self.store_log_event(tempevent)
else: else:
del self.internal_state['backlog'] del self.internal_state['backlog']
if event.levelno < format.WARNING:
return
if not 'build' in self.internal_state:
print "Save event for later"
if not 'backlog' in self.internal_state:
self.internal_state['backlog'] = []
self.internal_state['backlog'].append(event)
return
log_information = {} log_information = {}
log_information['build'] = self.internal_state['build'] log_information['build'] = self.internal_state['build']
if event.levelno >= format.ERROR: if event.levelno >= format.ERROR:
log_information['level'] = LogMessage.ERROR log_information['level'] = event.levelno
elif event.levelno == format.WARNING: elif event.levelno == format.WARNING:
log_information['level'] = LogMessage.WARNING log_information['level'] = LogMessage.WARNING
elif event.levelno == format.INFO:
log_information['level'] = LogMessage.INFO
else:
log_information['level'] = event.levelno
log_information['message'] = event.msg log_information['message'] = event.msg
log_information['pathname'] = event.pathname log_information['pathname'] = event.pathname
log_information['lineno'] = event.lineno log_information['lineno'] = event.lineno
self.orm_wrapper.create_logmessage(log_information) self.orm_wrapper.create_logmessage(log_information)
def close(self):
if self.brbe is not None:
buildinfohelper._store_build_done()
if 'backlog' in self.internal_state:
for event in self.internal_state['backlog']:
print "NOTE: Unsaved log: ", event.msg

View File

@ -94,7 +94,6 @@ def main(server, eventHandler, params ):
first = True first = True
buildinfohelper = BuildInfoHelper(server, build_history_enabled) buildinfohelper = BuildInfoHelper(server, build_history_enabled)
brbe = None
while True: while True:
try: try:
@ -111,7 +110,7 @@ def main(server, eventHandler, params ):
helper.eventHandler(event) helper.eventHandler(event)
if isinstance(event, bb.event.BuildStarted): if isinstance(event, bb.event.BuildStarted):
brbe = buildinfohelper.store_started_build(event) buildinfohelper.store_started_build(event)
if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)): if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
buildinfohelper.update_and_store_task(event) buildinfohelper.update_and_store_task(event)
@ -222,19 +221,18 @@ def main(server, eventHandler, params ):
bb.command.CommandExit)): bb.command.CommandExit)):
if (isinstance(event, bb.command.CommandFailed)): if (isinstance(event, bb.command.CommandFailed)):
event.levelno = format.ERROR event.levelno = format.ERROR
event.msg = event.error event.msg = "Command Failed " + event.error
event.pathname = "" event.pathname = ""
event.lineno = 0 event.lineno = 0
buildinfohelper.store_log_event(event) buildinfohelper.store_log_event(event)
errors += 1 errors += 1
buildinfohelper.update_build_information(event, errors, warnings, taskfailures) buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
buildinfohelper.close()
# we start a new build info # we start a new build info
if brbe is not None: if buildinfohelper.brbe is not None:
br_id, be_id = brbe.split(":")
buildinfohelper.store_build_done(br_id, be_id)
print "we are under BuildEnvironment management - after the build, we exit" print "we are under BuildEnvironment management - after the build, we exit"
server.terminateServer() server.terminateServer()