Grid: fix N bugs, metric sorting, slower.
Had to kill the caching code; it's been the source of no end of bugs in the grid for the last six months and I'm just not smart enough to fix it. Every call goes through (slurred) render now. :(
This commit is contained in:
parent
68c7c4e3be
commit
2497b2b119
1 changed files with 79 additions and 99 deletions
|
@ -3,7 +3,7 @@
|
|||
|
||||
var Grid = function(json) {
|
||||
// We want a per-grid slurred rendering.
|
||||
this.render = util.slur(200, this.render);
|
||||
this.render = util.slur(500, this.render);
|
||||
|
||||
view.View.call(this, json);
|
||||
this.query = json.query;
|
||||
|
@ -12,6 +12,8 @@
|
|||
this.rows_str = json.rows;
|
||||
this.cols_str = json.cols;
|
||||
this.max_fn = util.max_fn(json.max);
|
||||
this.row_sort = json.row_sort || "lexical";
|
||||
this.col_sort = json.col_sort || "lexical";
|
||||
this.row_fn = util.extract_fn(json.rows) || util.extract_fn('host');
|
||||
this.col_fn = util.extract_fn(json.cols) || util.extract_fn('service');
|
||||
this.clickFocusable = true;
|
||||
|
@ -30,8 +32,6 @@
|
|||
this.rows = [];
|
||||
// events[row_key][col_key] = event
|
||||
this.events = {};
|
||||
// elCache[row_key][col_key] = {td: , metric: }
|
||||
this.elCache = {};
|
||||
// maxima[maxima_value] = 500
|
||||
this.maxima = {};
|
||||
|
||||
|
@ -55,7 +55,9 @@
|
|||
query: this.query,
|
||||
max: this.max,
|
||||
rows: this.rows_str,
|
||||
cols: this.cols_str
|
||||
cols: this.cols_str,
|
||||
row_sort: this.row_sort,
|
||||
col_sort: this.col_sort
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -69,13 +71,29 @@
|
|||
"<label for='cols'>Columns</label>" +
|
||||
"<input type='text' name='cols' value=\"{{-cols_str}}\" /><br />" +
|
||||
"<span class='desc'>'host' or 'service'</span><br />" +
|
||||
"<label for='row_sort'>Sort rows</label>" +
|
||||
"<select name='row_sort'>" +
|
||||
"<option value='lexical' {{row_sort_lexical}}>Lexically</option>" +
|
||||
"<option value='metric' {{row_sort_metric}}>By metric</option>" +
|
||||
"</select><br />" +
|
||||
"<label for='col_sort'>Sort columns</label>" +
|
||||
"<select name='col_sort'>" +
|
||||
"<option value='lexical' {{col_sort_lexical}}>Lexically</option>" +
|
||||
"<option value='metric' {{col_sort_metric}}>By metric</option>" +
|
||||
"</select><br />" +
|
||||
"<label for='max'>Max</label>" +
|
||||
"<input type='text' name='max' value=\"{{-max}}\" /><br />" +
|
||||
"<span class='desc'>'all', 'host', 'service', or any number.</span>"
|
||||
);
|
||||
|
||||
Grid.prototype.editForm = function() {
|
||||
return editTemplate(this);
|
||||
return editTemplate(
|
||||
util.merge(this, {
|
||||
row_sort_lexical: (this.row_sort === "lexical" ? "selected" : ""),
|
||||
row_sort_metric: (this.row_sort === "metric" ? "selected" : ""),
|
||||
col_sort_lexical: (this.col_sort === "lexical" ? "selected" : ""),
|
||||
col_sort_metric: (this.col_sort === "metric" ? "selected" : "")
|
||||
}));
|
||||
};
|
||||
|
||||
// What is the maximum for this event?
|
||||
|
@ -85,24 +103,29 @@
|
|||
return this.max_fn;
|
||||
} else {
|
||||
// Use fn to group maxima
|
||||
return this.maxima[this.max_fn(event)] || -1/0;
|
||||
return this.maxima[this.max_fn(event)] || 1/0;
|
||||
}
|
||||
};
|
||||
|
||||
// Recomputes all maxima.
|
||||
Grid.prototype.refreshMaxima = function() {
|
||||
if (typeof(this.max_fn) === "number") {
|
||||
// We're done; no need to update a fixed maximum.
|
||||
return;
|
||||
}
|
||||
|
||||
this.maxima = {};
|
||||
var e;
|
||||
var max_key;
|
||||
var current_max;
|
||||
for (var name in this.events) {
|
||||
for (var subName in this.events[name]) {
|
||||
e = this.events[name][subName];
|
||||
for (var row in this.events) {
|
||||
for (var col in this.events[row]) {
|
||||
e = this.events[row][col];
|
||||
if (e.metric) {
|
||||
max_key = this.max_fn(e);
|
||||
current_max = this.maxima[max_key];
|
||||
if ((current_max === undefined) || (current_max < e.metric)) {
|
||||
this.maxima[current_max] = e.metric;
|
||||
this.maxima[max_key] = e.metric;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -151,101 +174,80 @@
|
|||
var cols = {};
|
||||
for (var row in this.events) {
|
||||
for (var col in this.events[row]) {
|
||||
cols[col] = true;
|
||||
cols[col] = Math.max(
|
||||
(cols[col] || -1/0), this.events[row][col].metric);
|
||||
}
|
||||
}
|
||||
this.cols = _.keys(cols).sort();
|
||||
}
|
||||
if (this.col_sort === "lexical") {
|
||||
this.cols = _.keys(cols).sort();
|
||||
} else {
|
||||
this.cols = _.sortBy(_.keys(cols), function(c) { return -cols[c]; });
|
||||
}
|
||||
};
|
||||
|
||||
// Full refresh of row list
|
||||
Grid.prototype.refreshRows = function() {
|
||||
// Recompute rows
|
||||
this.rows = _.keys(this.events).sort();
|
||||
}
|
||||
if (this.row_sort === "lexical") {
|
||||
this.rows = _.keys(this.events).sort();
|
||||
} else {
|
||||
var rows = {};
|
||||
for (var row in this.events) {
|
||||
for (var col in this.events[row]) {
|
||||
rows[row] = Math.max(
|
||||
(rows[row] || -1/0), this.events[row][col].metric);
|
||||
}
|
||||
}
|
||||
this.rows = _.sortBy(_.keys(rows), function(r) { return -rows[r]; });
|
||||
}
|
||||
};
|
||||
|
||||
// Returns a td for the given element.
|
||||
Grid.prototype.renderElement = function(event) {
|
||||
if (event === undefined) {
|
||||
// Nuke element
|
||||
return $('<td></td>');
|
||||
}
|
||||
|
||||
// Generates a td cell for an event. Returns a map of the td, bar, and metric
|
||||
// elements.
|
||||
Grid.prototype.newTdCache = function() {
|
||||
var td = $('<td><span class="bar"><span class="metric"/></span></td>');
|
||||
var bar = td.find('.bar');
|
||||
var metric = td.find('.metric');
|
||||
return {td: td, bar: bar, metric: metric};
|
||||
};
|
||||
|
||||
// Update a single jq element with information about an event.
|
||||
Grid.prototype.renderElement = function(e, event) {
|
||||
if (event === undefined) {
|
||||
// Nuke element
|
||||
e.metric.text('');
|
||||
e.bar.css('width', 0);
|
||||
e.td.attr('class', '');
|
||||
e.td.attr('title', '');
|
||||
return false;
|
||||
}
|
||||
|
||||
// State
|
||||
e.td.attr('class', "state box " + event.state);
|
||||
td.attr('class', "state box " + event.state);
|
||||
|
||||
// Description
|
||||
e.td.attr('title', event.host + ' ' + event.service + "\n" + event.state +
|
||||
td.attr('title', event.host + ' ' + event.service + "\n" + event.state +
|
||||
"\nreceived at " + new Date(event.time).toString() +
|
||||
"\nexpiring at " + new Date(event.time + event.ttl * 1000).toString() +
|
||||
(event.description ? ("\n\n" + event.description) : ""));
|
||||
|
||||
// Metric
|
||||
if (event.metric != undefined) {
|
||||
e.metric.text(format.float(event.metric));
|
||||
metric.text(format.float(event.metric));
|
||||
} else if (event.state != undefined) {
|
||||
e.metric.text(event.state);
|
||||
metric.text(event.state);
|
||||
}
|
||||
|
||||
// Bar chart
|
||||
if (event.metric === 0) {
|
||||
// Zero
|
||||
e.bar.css('width', 0);
|
||||
} else if (0 < event.metric) {
|
||||
// Positive
|
||||
e.bar.css('width',
|
||||
(event.metric / this.eventMax(event) * 100) + "%");
|
||||
if (event.metric === null ||
|
||||
event.metric === undefined ||
|
||||
event.metric <= 0) {
|
||||
bar.css('width', 0);
|
||||
} else {
|
||||
// Nil or negative
|
||||
e.bar.css('width', 0);
|
||||
}
|
||||
};
|
||||
|
||||
// Render a single event if there's been no change to table structure.
|
||||
Grid.prototype.partialRender = function(event) {
|
||||
var rowKey = this.row_fn(event);
|
||||
var colKey = this.col_fn(event);
|
||||
var cache = (this.elCache[rowKey] && this.elCache[rowKey][colKey]);
|
||||
if (!cache) {
|
||||
// No cached td element
|
||||
cache = this.newTdCache();
|
||||
|
||||
// Update cache
|
||||
if (!this.elCache[rowKey]) {
|
||||
this.elCache[rowKey] = {};
|
||||
}
|
||||
this.elCache[rowKey][colKey] = cache;
|
||||
|
||||
// Update table.
|
||||
var table = this.el.find('table');
|
||||
var rowIndex = this.rows.indexOf(rowKey);
|
||||
var columnIndex = this.cols.indexOf(colKey);
|
||||
var row = this.el.find('tbody tr')[rowIndex];
|
||||
$($(row).find('td')[columnIndex]).replaceWith(cache.td);
|
||||
// Positive
|
||||
bar.css('width',
|
||||
(event.metric / this.eventMax(event) * 100) + "%");
|
||||
}
|
||||
|
||||
this.renderElement(cache, event);
|
||||
return td;
|
||||
};
|
||||
|
||||
// A full re-rendering of the table.
|
||||
Grid.prototype.render = function() {
|
||||
// Update data model
|
||||
this.refreshMaxima();
|
||||
this.refreshRows();
|
||||
this.refreshCols();
|
||||
this.refreshMaxima();
|
||||
|
||||
var table = this.el.find('table');
|
||||
table.empty();
|
||||
|
@ -262,28 +264,13 @@
|
|||
row.append(element);
|
||||
});
|
||||
|
||||
this.rows.forEach(function(name, i) {
|
||||
this.rows.forEach(function(rowName, i) {
|
||||
row = $("<tr><th></th>");
|
||||
table.append(row);
|
||||
row.find('th').text(shortRowNames[i] || 'nil');
|
||||
this.cols.forEach(function(subName) {
|
||||
var event = this.events[name][subName];
|
||||
var cache = (this.elCache[name] && this.elCache[name][subName]);
|
||||
if (!cache) {
|
||||
// Not cached; generate and render.
|
||||
cache = this.newTdCache();
|
||||
|
||||
// Cache element
|
||||
if (!this.elCache[name]) {
|
||||
this.elCache[name] = {};
|
||||
}
|
||||
this.elCache[name][subName] = cache;
|
||||
|
||||
// Render element
|
||||
this.renderElement(cache, event);
|
||||
}
|
||||
row.append(cache.td);
|
||||
this.cols.forEach(function(colName) {
|
||||
row.append(this.renderElement(this.events[rowName][colName]));
|
||||
}, this);
|
||||
table.append(row);
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
@ -314,7 +301,8 @@
|
|||
if (newEvent || newMax) {
|
||||
this.render();
|
||||
} else {
|
||||
this.partialRender(e);
|
||||
// this.partialRender(e);
|
||||
this.render();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -331,14 +319,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Wipe element cache
|
||||
if (this.elCache[row_key]) {
|
||||
delete this.elCache[row_key][col_key];
|
||||
if (_.isEmpty(this.elCache[row_key])) {
|
||||
delete this.elCache[row_key];
|
||||
}
|
||||
}
|
||||
|
||||
this.render();
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue