Skip to content
This repository has been archived by the owner on Mar 31, 2024. It is now read-only.

Commit

Permalink
Merge branch 'pr/111': master node indication, multiple master detect…
Browse files Browse the repository at this point in the history
…ion, stale data indication

Closes elastic#105 , Closes elastic#104
  • Loading branch information
bleskes committed Feb 17, 2014
2 parents 8a0136d + 70cf21b commit 52db817
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 47 deletions.
2 changes: 1 addition & 1 deletion kibana/panels/navigation/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ define([
'angular',
'app',
'jquery',
'lodash',
'lodash'
],
function (angular, app, $, _) {
'use strict';
Expand Down
29 changes: 20 additions & 9 deletions kibana/panels/stats_table/module.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@
height: 10px;
width: 50px;
}
.marvel-muted .mutable {
opacity: 0.3;
}
</style>

<div class="pull-left marvel-header marvel-table" ng-show="rows.length > 0 || panel.rowFilter">
<input type="text" class="input-medium" placeholder="Filter {{panel.mode}}..." ng-model="panel.rowFilter" ng-change="onRowFilterChange()"> <span class="count">{{rows.length}} of {{_.size(data)}} {{panel.mode}}</span> / {{selectedData().length}} selected / Last 10m </span>
<input type="text" class="input-medium" placeholder="Filter {{panel.mode}}..." ng-model="panel.rowFilter" ng-change="onRowFilterChange()">
<span class="count">{{rows.length}} of {{_.size(data)}} {{panel.mode}}</span> / {{selectedData().length}} selected / Last 10m </span>
<span ng-show="meta.masterCount > 1"> / </span><span class="text-warning" ng-show="meta.masterCount > 1">Warning: Multiple masters. {{meta.masterCount}} nodes report master role</span></span>
<br>
<span class="small muted pull-right" ng-show="!viewSelect"> <i class="icon-warning"></i> Compact view. Filter {{panel.mode}} to 5 or less, or set the page refresh rate to 2m or greater for more options.</span>
</div>
Expand All @@ -58,17 +63,21 @@
<i ng-show='metric.field == panel.sort[0]' class="pointer link" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
</th>
</thead>
<tr ng-repeat="row in rows">
<tr ng-repeat="row in rows" ng-class="{'marvel-muted':!row.alive}">
<td>
<div class="checkbox">
<label>
<div>
<label class="checkbox" ng-class="alertClass(row.id_alert_level)">
<input type="checkbox" ng-model="row.selected" ng-checked="row.selected">
<span class="pointer" ng-click="rowClick(row)">{{row.display_name}}</span>
<span class="pointer" ng-click="rowClick(row)">
{{row.display_name}}
<i bs-tooltip="'No report has been received for more than '+staleSeconds+' seconds'" ng-show="!row.alive" class="icon-exclamation-sign"></i>
<i bs-tooltip="'This node is master'" ng-show="row.master" class="icon-star"></i>
</span>
<div class="marvel-persistent-name pointer" ng-hide="row.id == row.display_name" ng-click="rowClick(row)">{{row.id}}</div>
</label>
</div>
</td>
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)">
<td ng-repeat="metric in panel.metrics" class="mutable" ng-class="alertClass(row[metric.field].alert_level)">
<div class="marvel-mean pointer" ng-click="rowClick(row,metric)">
<span bo-text="(_.isNull(row[metric.field].mean)?'n/a':row[metric.field].mean) | metric_format:metric"></span>
<br>
Expand Down Expand Up @@ -97,16 +106,18 @@
<i ng-show='metric.field == panel.sort[0]' class="pointer link" ng-class="{'icon-chevron-up': panel.sort[1] == 'asc','icon-chevron-down': panel.sort[1] == 'desc'}"></i>
</th>
</thead>
<tr ng-repeat="row in rows">
<tr ng-repeat="row in rows" ng-class="{'marvel-muted':!row.alive}">
<td>
<div class="checkbox">
<div class="checkbox" ng-class="alertClass(row.id_alert_level)">
<label>
<input type="checkbox" ng-model="row.selected" ng-checked="row.selected">
</label>
<span class="pointer" ng-click="rowClick(row)">{{ row.id }}</span>
<i bs-tooltip="'No report has been received for more than '+staleSeconds+' seconds'" ng-show="!row.alive" class="icon-exclamation-sign"></i>
<i bs-tooltip="'This node is master'" ng-show="row.master" class="icon-star"></i>
</div>
</td>
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)">
<td ng-repeat="metric in panel.metrics" ng-class="alertClass(row[metric.field].alert_level)" class="mutable">
<div class="pointer" ng-click="rowClick(row,metric)">
<span bo-text="(_.isNull(row[metric.field].mean)?'n/a':row[metric.field].mean) | metric_format:metric"></span>

Expand Down
136 changes: 99 additions & 37 deletions kibana/panels/stats_table/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ define([
add: undefined
};

$scope.staleIntervalCount = 5;

$scope.modeInfo = {
nodes: {
defaults: {
Expand Down Expand Up @@ -340,23 +342,32 @@ define([

filter = filterSrv.getBoolFilter(filterSrv.ids);

var to = filterSrv.timeRange(false).to;
var maxFilterTime, to;
maxFilterTime = to = filterSrv.timeRange(false).to;
maxFilterTime = kbn.parseDate(maxFilterTime).getTime();
if (to !== "now") {
to = kbn.parseDate(to).valueOf() + "||";
}

filter.must($scope.get_mode_filter()).must($scope.ejs.RangeFilter('@timestamp').from(to + "-10m/m").to(to + "/m"));

request = $scope.ejs.Request().indices(dashboard.indices).size(0).searchType("count");
request = $scope.ejs.Request().indices(dashboard.indices).size(10);
request.query($scope.ejs.FilteredQuery($scope.ejs.MatchAllQuery(), filter));


// timestamp facet to give us the proper time ranges for each node
request.facet($scope.ejs.TermStatsFacet("timestamp")
.keyField($scope.panel.persistent_field).valueField("@timestamp")
.order('term')
.size(2000));

// master node detection
if ($scope.panel.mode === "nodes") {
request.facet($scope.ejs.TermStatsFacet("master_periods")
.keyField($scope.panel.persistent_field).valueField("@timestamp")
.order('term').facetFilter($scope.ejs.TermFilter("node.master", "true"))
.size(2000));

}

_.each($scope.panel.metrics, function (m) {
request.facet($scope.ejs.TermStatsFacet(m.field)
Expand All @@ -371,22 +382,59 @@ define([

var mrequest, newData;


// populate the summary data based on the other facets
newData = {};


_.each(r.facets['timestamp'].terms, function (f) {
if (!$scope.panel.show_hidden && f.term[0] === ".") {
return;
}
var t_interval = (f.max - f.min) / f.count;
if (t_interval <= 0) {
t_interval = 5000;
}
var alive = (maxFilterTime - f.max > $scope.staleIntervalCount * t_interval) ? false : true;
newData[f.term] = {
id: f.term,
time_span: (f.max - f.min) / 1000,
reporting_interval: t_interval / 1000,
alive: alive,
selected: ($scope.data[f.term] || {}).selected,
alert_level: 0
alert_level: alive ? 0 : 1,
id_alert_level: alive ? 0 : 1
};
});

if (r.facets['master_periods']) {
var most_recent_master = _.max(r.facets['master_periods'].terms, function (f) {
return f.max;
});
newData[most_recent_master.term].master = true;
// now check we have other active master within the same time frame
var other_masters = _.filter(r.facets['master_periods'].terms, function (t) {
if (t.term === most_recent_master.term) {
return false;
}
if (maxFilterTime - t.max > $scope.staleIntervalCount * newData[t.term].reporting_interval * 1000) {
// stale master info, we don't care.
return false;
}
// enough of overlap to not be a master swap
return (t.max - most_recent_master.min > $scope.staleIntervalCount * newData[t.term].reporting_interval * 1000);
});
_.each(other_masters, function (t) {
newData[t.term].master = true;
});
if (other_masters.length > 0) {
// mark all master nodes as alerting
_.each(newData, function (n) {
if (n.master) {
n.alert_level = n.id_alert_level = 2;
}
});
}
}

_.each($scope.panel.metrics, function (m) {
_.each(r.facets[m.field].terms, function (f) {
Expand Down Expand Up @@ -423,12 +471,6 @@ define([
}
summary[m.field] = m_summary;
m_summary.alert_level = $scope.alertLevel(m, m_summary.mean);
// if (f.term === "index_t_200" && m.field === "primaries.docs.count") {
// m_summary.alert_level = 1;
// }
// if (f.term === "index_t_300" && m.field === "primaries.indexing.index_total") {
// m_summary.alert_level = 2;
// }
if (m_summary.alert_level > summary.alert_level) {
summary.alert_level = m_summary.alert_level;
}
Expand Down Expand Up @@ -466,41 +508,52 @@ define([
$scope.ejs.TermQuery($scope.panel.persistent_field, s.id)
)
);
rowRequest.size(1).fields(_.unique([ stripRaw($scope.panel.display_field), stripRaw($scope.panel.persistent_field)]));
rowRequest.size(1).fields(_.unique(
[ stripRaw($scope.panel.display_field), stripRaw($scope.panel.persistent_field)]
));

rowRequest.sort("@timestamp", "desc");

mrequest.requests(rowRequest);
});

mrequest.doSearch(function (r) {
var
hit,
display_name,
persistent_name;

_.each(r.responses, function (response) {
if (response.hits.hits.length === 0) {
return;
}

hit = response.hits.hits[0];
if (esVersion.gte("1.0.0.RC1")) {
display_name = (hit.fields[stripRaw($scope.panel.display_field)] || [ undefined ])[0];
persistent_name = (hit.fields[stripRaw($scope.panel.persistent_field)] || [ undefined] )[0];
}
else {
display_name = hit.fields[stripRaw($scope.panel.display_field)];
persistent_name = hit.fields[stripRaw($scope.panel.persistent_field)];
}
(newData[persistent_name] || {}).display_name = display_name;
esVersion.is('>=1.0.0.RC1').then(function (version) {
var
hit,
display_name,
persistent_name;

_.each(r.responses, function (response) {
if (response.hits.hits.length === 0) {
return;
}

hit = response.hits.hits[0];
if (version) {
display_name = (hit.fields[stripRaw($scope.panel.display_field)] || [ undefined ])[0];
persistent_name = (hit.fields[stripRaw($scope.panel.persistent_field)] || [ undefined] )[0];
}
else {
display_name = hit.fields[stripRaw($scope.panel.display_field)];
persistent_name = hit.fields[stripRaw($scope.panel.persistent_field)];
}
(newData[persistent_name] || {}).display_name = display_name;
});
$scope._register_data_end();
$scope.select_display_data_and_enrich(newData);
});
$scope._register_data_end();
$scope.select_display_data_and_enrich(newData);
}, $scope._register_data_end);
}, $scope._register_data_end);

};

function applyNewData(rows, data) {
$scope.meta = {
masterCount: _.filter(data, {master: true, alive: true}).length
};

$scope.rows = rows;
$scope.data = data;
$scope.updateUIFeaturesBasedOnData();
Expand Down Expand Up @@ -583,6 +636,17 @@ define([
return 0;
}

function compareIdByMasterRole(id1, id2) {
var s1 = newData[id1], s2 = newData[id2];
if (s1.master && !s2.master) {
return -1;
}
if (!s1.master && s2.master) {
return 1;
}
return 0;
}

function compareIdByPanelSort(id1, id2) {
var v1 = $scope.get_sort_value(id1, newData),
v2 = $scope.get_sort_value(id2, newData),
Expand Down Expand Up @@ -614,12 +678,12 @@ define([
}

if ($scope.panel.sort) {
newRowsIds.sort(concatSorting(compareIdByPanelSort, compareIdByAlert, compareIdBySelection));
newRowsIds.sort(concatSorting(compareIdByPanelSort, compareIdByAlert, compareIdBySelection, compareIdByMasterRole));
newRowsIds = newRowsIds.slice(0, $scope.rowLimit);

}
else {
newRowsIds.sort(concatSorting(compareIdBySelection, compareIdByAlert, compareIdByName));
newRowsIds.sort(concatSorting(compareIdBySelection, compareIdByAlert, compareIdByMasterRole, compareIdByName));
newRowsIds = newRowsIds.slice(0, $scope.rowLimit);
// sort again for visual effect
// sort again for visual placement
Expand All @@ -631,8 +695,6 @@ define([
return newData[id];
});

// now that we have selections, sort by name (if


request = $scope.ejs.Request().indices(dashboard.indices);
var to = filterSrv.timeRange(false).to;
Expand Down

0 comments on commit 52db817

Please sign in to comment.