bitbake: toaster: display Toaster exceptions and other fixes

Changing ToasterUI to log toaster exceptions on a different level than
build errors.

Updating the build dashboard to show Toaster exceptions.

We add extra logging to console for exceptions.

Fixed a problem where packages database entries were created instead of
being looked up in the database, conficting with entries created to
satisfy dependency information.

Toaster now checks for invalid states at startup and performs needed
cleanups.

Removed loading reference to jquery-ui.min.css as we do not have this
file.

(Bitbake rev: 2378812bc24d433125fb940f110154f0ce638448)

Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Alexandru DAMIAN 2014-11-25 10:12:46 +00:00 committed by Richard Purdie
parent 707a960ffa
commit af1f9fda8b
8 changed files with 77 additions and 8 deletions

View File

@ -381,7 +381,7 @@ class ORMWrapper(object):
searchname = pkgpnmap[p]['OPKGN']
packagedict[p]['object'], created = Package.objects.get_or_create( build = build_obj, name = searchname )
if created or package[p]['object'].size == -1: # save the data anyway we can, not just if it was not created here; bug [YOCTO #6887]
if created or packagedict[p]['object'].size == -1: # save the data anyway we can, not just if it was not created here; bug [YOCTO #6887]
# fill in everything we can from the runtime-reverse package data
try:
packagedict[p]['object'].recipe = recipes[pkgpnmap[p]['PN']]
@ -462,7 +462,7 @@ class ORMWrapper(object):
if 'OPKGN' in package_info.keys():
pname = package_info['OPKGN']
bp_object = Package.objects.create( build = build_obj,
bp_object, created = Package.objects.get_or_create( build = build_obj,
name = pname )
bp_object.installed_name = package_info['PKG']
@ -1043,6 +1043,15 @@ class BuildInfoHelper(object):
mockevent.lineno = -1
self.store_log_event(mockevent)
def store_log_exception(self, text, backtrace = ""):
mockevent = MockEvent()
mockevent.levelno = -1
mockevent.msg = text
mockevent.pathname = backtrace
mockevent.lineno = -1
self.store_log_event(mockevent)
def store_log_event(self, event):
if event.levelno < format.WARNING:
return
@ -1078,6 +1087,8 @@ class BuildInfoHelper(object):
log_information['level'] = LogMessage.ERROR
elif event.levelno == format.WARNING:
log_information['level'] = LogMessage.WARNING
elif event.levelno == -1: # toaster self-logging
log_information['level'] = -1
else:
log_information['level'] = LogMessage.INFO

View File

@ -299,12 +299,13 @@ def main(server, eventHandler, params ):
logger.error(e)
import traceback
exception_data = traceback.format_exc()
print(exception_data)
# save them to database, if possible; if it fails, we already logged to console.
try:
buildinfohelper.store_log_error("%s\n%s" % (str(e), exception_data))
except Exception:
pass
buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data))
except Exception as ce:
print("CRITICAL: failed to to save toaster exception to the database: %s" % str(ce))
pass

View File

@ -139,4 +139,12 @@ class Command(NoArgsCommand):
ToasterSetting.objects.filter(name = 'DEFAULT_RELEASE').delete()
ToasterSetting.objects.get_or_create(name = 'DEFAULT_RELEASE', value = '')
# we are just starting up. we must not have any builds in progress, or build environments taken
for b in BuildRequest.objects.filter(state = BuildRequest.REQ_INPROGRESS):
BRError.objects.create(req = b, errtype = "toaster", errmsg = "Toaster found this build IN PROGRESS while Toaster started up. This is an inconsistent state, and the build was marked as failed")
BuildRequest.objects.filter(state = BuildRequest.REQ_INPROGRESS).update(state = BuildRequest.REQ_FAILED)
BuildEnvironment.objects.update(lock = BuildEnvironment.LOCK_FREE)
return 0

View File

@ -178,6 +178,11 @@ class Build(models.Model):
tgts = Target.objects.filter(build_id = self.id).order_by( 'target' );
return( tgts );
@property
def toaster_exceptions(self):
return self.logmessage_set.filter(level=LogMessage.EXCEPTION)
class ProjectTarget(models.Model):
project = models.ForeignKey(Project)
target = models.CharField(max_length=100)
@ -966,13 +971,15 @@ class HelpText(models.Model):
text = models.TextField()
class LogMessage(models.Model):
EXCEPTION = -1 # used to signal self-toaster-exceptions
INFO = 0
WARNING = 1
ERROR = 2
LOG_LEVEL = ( (INFO, "info"),
(WARNING, "warn"),
(ERROR, "error") )
(ERROR, "error"),
(EXCEPTION, "toaster exception"))
build = models.ForeignKey(Build)
task = models.ForeignKey(Task, blank = True, null=True)

View File

@ -252,6 +252,13 @@ $(document).ready(function() {
$('.toggle-warnings').click(function() {
$('#collapse-warnings').toggleClass('in');
});
$('.show-exceptions').click(function() {
$('#collapse-exceptions').addClass('in');
});
$('.toggle-exceptions').click(function() {
$('#collapse-exceptions').toggleClass('in');
});
//show warnings section when requested from the previous page
if (location.href.search('#warnings') > -1) {
$('#collapse-warnings').addClass('in');

View File

@ -8,7 +8,7 @@
<link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}" type='text/css'>
<link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'>
<link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'>
<link rel="stylesheet" href="assets/css/jquery-ui-1.10.3.custom.min.css" type='text/css'>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<script src="{% static 'js/jquery-2.0.3.min.js' %}">

View File

@ -39,6 +39,14 @@
<span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span>
{%endif%}
</div>
{% if build.toaster_exceptions.count > 0 %}
<div class="row">
<small class="pull-right">
<i class="icon-question-sign get-help get-help-blue" title="" data-original-title="Toaster exceptions do not affect your build: only the operation of Toaster"></i>
<a class="show-exceptions" href="#exceptions">Toaster threw {{build.toaster_exceptions.count}} exception{{build.toaster_exceptions.count|pluralize}}</a>
</small>
</div>
{% endif %}
</div>
</div>
@ -223,6 +231,33 @@
</div>
{% endif %}
{% if build.toaster_exceptions.count > 0 %}
<div class="accordion span10 pull-right" id="exceptions">
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle exception toggle-exceptions">
<h2 id="exception-toggle">
<i class="icon-warning-sign"></i>
{{build.toaster_exceptions.count}} Toaster exception{{build.toaster_exceptions.count|pluralize}}
</h2>
</a>
</div>
<div class="accordion-body collapse" id="collapse-exceptions">
<div class="accordion-inner">
<div class="span10">
{% for exception in build.toaster_exceptions %}
<div class="alert alert-exception">
<pre>{{exception.message}}</pre>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{% endif %}
<script type="text/javascript">
$(document).ready(function() {
//show warnings section when requested from the previous page

View File

@ -461,7 +461,7 @@ def builddashboard( request, build_id ):
template = "builddashboard.html"
if Build.objects.filter( pk=build_id ).count( ) == 0 :
return redirect( builds )
build = Build.objects.filter( pk = build_id )[ 0 ];
build = Build.objects.get( pk = build_id );
layerVersionId = Layer_Version.objects.filter( build = build_id );
recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( );
tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' );