Add filter functionality to test-details pythonlogging

On tests with pythonlogging, the DEBUG headers can be quite long and
make finding useful information difficult. This patch adds a small,
four-button filter to the test-details page that allows a user to
select which levels of logging to be displayed (INFO, WARNING, ERROR,
DEBUG). This patch will likely serve as the base for additional search
functionality for test details (e.g. queries).

Change-Id: Ia4286861268de0e43313d3b8d7f966e94697a495
This commit is contained in:
Austin Clark 2016-01-15 13:20:21 -07:00
parent 728eb59ae8
commit 6b80ea8fa2
7 changed files with 142 additions and 15 deletions

View File

@ -8,14 +8,14 @@ var controllersModule = require('./_index');
function TestDetailsCtrl($scope, $location, $stateParams, datasetService) {
// ViewModel
var vm = this;
vm.datasetId = $stateParams.datasetId;
$scope.datasetId = $stateParams.datasetId;
var testName = $stateParams.test;
vm.testName = testName;
$scope.testName = testName;
// load dataset, raw json, and details json
datasetService.get($stateParams.datasetId).then(function(response) {
vm.dataset = response;
vm.stats = response.stats;
$scope.dataset = response;
$scope.stats = response.stats;
datasetService.raw(response).then(function(raw) {
var item = null;
for (var t in raw.data) {
@ -23,13 +23,14 @@ function TestDetailsCtrl($scope, $location, $stateParams, datasetService) {
item = raw.data[t];
}
}
vm.item = item;
$scope.item = item;
}).catch(function(ex) {
$log.error(ex);
});
datasetService.details(response).then(function(deets) {
vm.details = deets;
vm.itemDetails = deets.data[testName];
$scope.details = deets;
$scope.originalDetails = angular.copy(deets.data[testName]);
$scope.itemDetails = deets.data[testName];
}).catch(function(ex) {
$log.error(ex);
});
@ -37,5 +38,29 @@ function TestDetailsCtrl($scope, $location, $stateParams, datasetService) {
$log.error(ex);
});
$scope.parsePythonLogging = function(showINFO, showDEBUG, showWARNING, showERROR) {
if ($scope.originalDetails && $scope.originalDetails.pythonlogging) {
var log = $scope.originalDetails.pythonlogging;
var ret = [];
var lines = log.split('\n');
for (var i in lines) {
var line = lines[i];
if (showINFO && line.includes("INFO")) {
ret.push(line);
}
else if (showDEBUG && line.includes("DEBUG")) {
ret.push(line);
}
else if (showWARNING && line.includes("WARNING")) {
ret.push(line);
}
else if (showERROR && line.includes("ERROR")) {
ret.push(line);
}
}
$scope.itemDetails.pythonlogging = ret.join('\n');
}
};
}
controllersModule.controller('TestDetailsCtrl', TestDetailsCtrl);

View File

@ -0,0 +1,46 @@
'use strict';
var directivesModule = require('./_index.js');
/**
* @ngInject
*/
function testDetailsSearch() {
/**
* @ngInject
*/
var controller = function($scope, $element) {
var self = this;
this.open = false;
this.showINFO = true;
this.showDEBUG = true;
this.showWARNING = true;
this.showERROR = true;
var update = function() {
$scope.$parent
.parsePythonLogging(self.showINFO, self.showDEBUG, self.showWARNING, self.showERROR);
};
$scope.$watch(function() { return self.query; }, update);
$scope.$watch(function() { return self.showINFO; }, update);
$scope.$watch(function() { return self.showDEBUG; }, update);
$scope.$watch(function() { return self.showWARNING; }, update);
$scope.$watch(function() { return self.showERROR; }, update);
};
return {
restrict: 'EA',
require: ['^testDetailsSearch', '^testDetails'],
scope: {
'parsePythonLogging': '&'
},
controller: controller,
controllerAs: 'search',
templateUrl: 'directives/test-details-search.html',
transclude: true
};
}
directivesModule.directive('testDetailsSearch', testDetailsSearch);

View File

@ -0,0 +1,28 @@
test-details-search {
display: inline-block;
.popover {
max-width: 600px;
.test-details-search-popover {
width: 400px;
.input-group {
width: 100%;
}
.status-group label {
font-family: monospace;
}
.jump-group li {
cursor: pointer;
}
.jump-group ul {
max-height: 20em;
overflow-x: hidden;
overflow-y: auto;
}
}
}
}

View File

@ -4,6 +4,7 @@
@import 'font-awesome/font-awesome';
@import 'sb-admin-2';
@import 'directives/_test-details-search.scss';
@import 'directives/_timeline-details.scss';
@import 'directives/_timeline-search.scss';
@import 'directives/_timeline-viewport.scss';

View File

@ -0,0 +1,19 @@
<div class="test-details-search-popover">
<label>Filter pythonlogging by log level:</label>
<div class="status-group btn-group btn-group-justified">
<label uib-btn-checkbox
ng-model="search.showINFO"
class="btn btn-default">INFO</label>
<label uib-btn-checkbox
ng-model="search.showDEBUG"
class="btn btn-default">DEBUG</label>
<label uib-btn-checkbox
ng-model="search.showWARNING"
class="btn btn-default">WARNING</label>
<label uib-btn-checkbox
ng-model="search.showERROR"
class="btn btn-default">ERROR</label>
</div>
</div>

View File

@ -0,0 +1,7 @@
<a uib-popover-template="'directives/test-details-search-popover.html'"
popover-placement="bottom-right"
popover-title="Filter Options"
popover-is-open="search.open">
<fa name="search"></fa>
<fa name="caret-down"></fa>
</a>

View File

@ -10,7 +10,8 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">
{{testDetails.testName | split:'.' | slice:-2 | join:'.'}}
{{testName | split:'.' | slice:-2 | join:'.'}}
<test-details-search class="pull-right"></test-details-search>
</h3>
</div>
@ -20,26 +21,26 @@
<table class="table table-bordered table-hover table-striped">
<tr>
<td>Name</td>
<td>{{testDetails.item.name | split:'.' | pickRight:1}}</td>
<td>{{item.name | split:'.' | pickRight:1}}</td>
<tr>
<td>Full Name</td>
<td>{{testDetails.item.name}}</td>
<td>{{item.name}}</td>
</tr>
<tr>
<td>Status</td>
<td>{{testDetails.item.status}}</td>
<td>{{item.status}}</td>
</tr>
<tr>
<td>Tags</td>
<td>{{testDetails.item.tags | join:', '}}</td>
<td>{{item.tags | join:', '}}</td>
</tr>
<tr>
<td>Duration</td>
<td>{{testDetails.item.duration | number:1}} seconds</td>
<td>{{item.duration | number:1}} seconds</td>
</tr>
</table>
</uib-tab>
<uib-tab ng-repeat="(entry,log) in testDetails.itemDetails" heading="{{entry}}">
<uib-tab ng-repeat="(entry,log) in itemDetails" heading="{{entry}}">
<pre style="height: 400px; overflow-y: scroll;">{{log}}</pre>
</uib-tab>
</uib-tabset>
@ -47,7 +48,7 @@
<div class="panel-footer clearfix">
<a class="btn btn-default pull-right"
ui-sref="timeline({datasetId: testDetails.dataset.id, test: testDetails.item.name})">
ui-sref="timeline({datasetId: dataset.id, test: item.name})">
Timeline
</a>
</div>