Skip to content

Commit 27b01aa

Browse files
committed
Version 1.0.9
- Added new colored annotations for servers that appear in the middle of a real-time data view. - Added "Annoations" checkbox so all annotations may be hidden or shown (saved per user in local storage). - Graph snapshots now show the date/time of the *right* side of the graph, not the left. - Group menus are now sorted alphabetically by ID. - Medium graph size line thickness reduced by 1px (looks better with many servers). - Group View: In real-time view, servers with "stale" data (over 10 min old) are shown as grayed out in the host table. - Server View: In real-time view, a warning is displayed when servers have "stale" data (over 10 min old). - Bug fix: Crash when trying to re-order groups in Admin/Groups tab.
1 parent 7400ae7 commit 27b01aa

File tree

8 files changed

+116
-51
lines changed

8 files changed

+116
-51
lines changed

htdocs/index-dev.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
<div id="d_ctrl_opts" style="float:right; margin-right:20px; display:none">
168168
<div class="info_label">Options</div>
169169
<div class="info_value" style="margin-bottom:0px;">
170-
<table cellspacing="0" cellpadding="0" style="border-collapse:collapse;"><tr><td><input type="checkbox" id="fe_ctrl_auto_refresh" value="1" onChange="$P().toggleAutoRefresh()"/></td><td><label for="fe_ctrl_auto_refresh" style="font-size:12px;">Auto-Refresh</label></td></tr></table>
170+
<table cellspacing="0" cellpadding="0" style="border-collapse:collapse;"><tr><td><input type="checkbox" id="fe_ctrl_auto_refresh" value="1" onChange="$P().toggleAutoRefresh()"/></td><td><label for="fe_ctrl_auto_refresh" style="font-size:12px; font-weight:normal">Auto-Refresh</label></td><td style="padding-left:12px;"><input type="checkbox" id="fe_ctrl_annotations" value="1" onChange="$P().toggleAnnotations()"/></td><td><label for="fe_ctrl_annotations" style="font-size:12px; font-weight:normal">Annotations</label></td></tr></table>
171171
</div>
172172
</div>
173173

htdocs/js/app.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ app.extend({
1212
default_prefs: {
1313
graph_size: 'half',
1414
ov_graph_size: 'third',
15-
auto_refresh: '1' // localStorage is ALWAYS STRINGS (ugh)
15+
auto_refresh: '1', // localStorage is ALWAYS STRINGS (ugh)
16+
annotations: '1'
1617
},
1718
debug_cats: {
1819
all: 1,
@@ -143,6 +144,11 @@ app.extend({
143144

144145
var old_group = $('#fe_ctrl_group').val();
145146
$('#fe_ctrl_group').empty();
147+
148+
this.config.groups.sort( function(a, b) {
149+
return a.id.localeCompare( b.id );
150+
} );
151+
146152
this.config.groups.forEach( function(group_def) {
147153
$('#fe_ctrl_group').append( '<option value="' + group_def.id + '">' + group_def.title + '</option>' );
148154
});
@@ -225,6 +231,11 @@ app.extend({
225231
$('#fe_jump_to_group').empty().append(
226232
'<option value="" disabled>Jump to Group</option>'
227233
);
234+
235+
this.config.groups.sort( function(a, b) {
236+
return a.id.localeCompare( b.id );
237+
} );
238+
228239
this.config.groups.forEach( function(group_def) {
229240
$('#fe_jump_to_group').append( '<option value="' + group_def.id + '">' + group_def.title + '</option>' );
230241
});

htdocs/js/heartbeat.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

htdocs/js/pages/Base.class.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Class.subclass( Page, "Page.Base", {
1515
},
1616
half: {
1717
height: 300,
18-
line_thickness: 3,
18+
line_thickness: 2,
1919
xaxis_ticks: 6,
2020
title_font_size: '15px'
2121
},
@@ -552,6 +552,7 @@ Class.subclass( Page, "Page.Base", {
552552
// auto-refresh checkbox
553553
$('#d_ctrl_opts').show();
554554
$('#fe_ctrl_auto_refresh').prop('checked', app.getPref('auto_refresh') == '1' );
555+
$('#fe_ctrl_annotations').prop('checked', app.getPref('annotations') == '1' );
555556
}
556557
else {
557558
$('#d_ctrl_range').hide();
@@ -650,6 +651,19 @@ Class.subclass( Page, "Page.Base", {
650651
}
651652
},
652653

654+
toggleAnnotations: function() {
655+
// toggle annotations user preference, read from checkbox
656+
if ($('#fe_ctrl_annotations').is(':checked')) {
657+
app.setPref('annotations', '1'); // always strings
658+
}
659+
else {
660+
app.setPref('annotations', '0'); // always strings
661+
}
662+
663+
// trigger a graph redraw
664+
this.onThemeChange();
665+
},
666+
653667
displayDataRange: function(min_date, max_date) {
654668
// display current data range
655669
// (min and max should be epoch seconds)
@@ -1021,14 +1035,16 @@ Class.subclass( Page, "Page.Base", {
10211035
// show indeterminate progress in icon
10221036
$elem.removeClass().addClass('mdi mdi-clipboard-arrow-up-outline mdi-lg');
10231037

1024-
// find left side of data for timestamp
1025-
var min_x = (new Date()).getTime();
1038+
// find right side of data for timestamp
1039+
var max_x = 0;
10261040
graph.w.config.series.forEach( function(dataset) {
1027-
if (dataset.data && dataset.data[0] && dataset.data[0].x && (dataset.data[0].x < min_x)) min_x = dataset.data[0].x;
1041+
if (dataset.data && dataset.data.length && (dataset.data[dataset.data.length - 1].x > max_x)) {
1042+
max_x = dataset.data[dataset.data.length - 1].x;
1043+
}
10281044
} );
10291045

1030-
// get date stamp of left side of chart
1031-
var dargs = get_date_args( new Date(min_x) );
1046+
// get date stamp of right side of chart
1047+
var dargs = get_date_args( new Date(max_x) );
10321048

10331049
// generate title, path and filename
10341050
var unique_id = get_unique_id(16, app.username);
@@ -1056,14 +1072,14 @@ Class.subclass( Page, "Page.Base", {
10561072
switch (args.sys) {
10571073
case 'hourly':
10581074
path = dargs.yyyy_mm_dd;
1059-
title += ' - ' + get_nice_date(min_x / 1000);
1075+
title += ' - ' + get_nice_date(max_x / 1000);
10601076
path += '/' + dargs.hh;
10611077
title += ' - ' + dargs.hour12 + ' ' + dargs.ampm.toUpperCase();
10621078
break;
10631079

10641080
case 'daily':
10651081
path = dargs.yyyy_mm_dd;
1066-
title += ' - ' + get_nice_date(min_x / 1000);
1082+
title += ' - ' + get_nice_date(max_x / 1000);
10671083
break;
10681084

10691085
case 'monthly':

htdocs/js/pages/Group.class.js

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ Class.subclass( Page.Base, "Page.Group", {
324324
var graph = this.graphs[mon_id];
325325
var series = [];
326326
var alert_times = [];
327+
var min_date = time_now();
327328

328329
// see if graph is still visible (queue delay -- user could have scrolled past)
329330
if (!this.div.find('#d_graph_group_' + mon_id).visible(true, true)) {
@@ -345,6 +346,8 @@ Class.subclass( Page.Base, "Page.Group", {
345346
if ((mon_id in row.totals) && self.isRowInRange(row)) {
346347
graph_rows.push({ x: row.date * 1000, y: row.totals[mon_id] });
347348

349+
if (row.date < min_date) min_date = row.date;
350+
348351
if (row.alerts) {
349352
var yes_alert = false;
350353

@@ -361,7 +364,7 @@ Class.subclass( Page.Base, "Page.Group", {
361364
name: self.formatHostname( host.hostname ),
362365
data: self.crushData( graph_rows )
363366
});
364-
});
367+
}); // foreach host
365368

366369
// possibly merge all series into single dataset (min/avg/max/total)
367370
if (app.getPref('ggt_' + mon_id)) {
@@ -370,21 +373,48 @@ Class.subclass( Page.Base, "Page.Group", {
370373

371374
// setup annotations
372375
var x_annos = [];
373-
alert_times.forEach( function(x) {
374-
x_annos.push({
375-
x: x,
376-
borderColor: '#888',
377-
yAxisIndex: 0,
378-
label: {
379-
show: true,
380-
text: 'Alert',
381-
style: {
382-
color: "#fff",
383-
background: '#f00'
376+
if (app.getPref('annotations') == '1') {
377+
alert_times.forEach( function(x) {
378+
x_annos.push({
379+
x: x,
380+
borderColor: '#888',
381+
yAxisIndex: 0,
382+
label: {
383+
show: true,
384+
text: 'Alert',
385+
style: {
386+
color: "#fff",
387+
background: '#f00'
388+
}
384389
}
385-
}
390+
});
386391
});
387-
});
392+
393+
if (this.isRealTime()) {
394+
// allow a few minutes of slack here, just in case a server had a hiccup
395+
var min_x = (min_date + 180) * 1000;
396+
397+
series.forEach( function(item, idx) {
398+
var rows = item.data;
399+
if (rows.length && (rows[0].x > min_x)) {
400+
x_annos.push({
401+
x: rows[0].x,
402+
borderColor: '#888',
403+
yAxisIndex: 0,
404+
label: {
405+
show: true,
406+
text: 'New',
407+
style: {
408+
color: "#fff",
409+
// background: '#080'
410+
background: self.graphColors[ idx % self.graphColors.length ]
411+
}
412+
}
413+
}); // x_annos.push
414+
} // new host
415+
} ); // foreach series
416+
} // real-time
417+
} // annotations enabled
388418

389419
// redraw graph series and annos
390420
var options = this.getGraphConfig(mon_id);
@@ -747,18 +777,20 @@ Class.subclass( Page.Base, "Page.Group", {
747777
if (extra_server_info.source) {
748778
nice_kernel = substitute(extra_server_info.source, metadata.data, false);
749779
}
750-
// var num_alerts = num_keys(metadata.alerts || {});
751-
var num_alerts = 0;
752-
html += '<tr ' + (num_alerts ? 'class="red"' : '') + '>';
780+
var is_stale = false;
781+
if (self.isRealTime() && host.rows && host.rows.length) {
782+
var row = host.rows[ host.rows.length - 1 ];
783+
if (row.date < time_now() - 600) is_stale = true;
784+
}
785+
786+
html += '<tr ' + (is_stale ? 'class="disabled"' : '') + '>';
753787
html += '<td><b>' + self.getNiceHostname(host.hostname, host.idx) + '</b></td>';
754788
html += '<td>' + (metadata.ip || 'n/a') + '</td>';
755-
// html += '<td>' + short_float(metadata.data.load ? metadata.data.load[0] : 0) + '</td>';
756789
html += '<td>' + (metadata.data.cpu ? metadata.data.cpu.cores : 0) + '</td>';
757790
html += '<td>' + get_text_from_bytes(metadata.data.memory.total || 0) + '</td>';
758791
html += '<td>' + nice_os + '</td>';
759792
html += '<td>' + nice_kernel + '</td>';
760793
html += '<td>' + get_text_from_seconds(metadata.data.uptime_sec || 0, false, true) + '</td>';
761-
// html += '<td>' + num_alerts + '</td>';
762794
html += '</tr>';
763795
});
764796

htdocs/js/pages/Server.class.js

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ Class.subclass( Page.Base, "Page.Server", {
170170
this.div.find('div.graph_container').addClass('dirty');
171171
this.onScrollDebounce();
172172
this.updateInfo();
173+
174+
// show warning if server data is stale (only in real-time mode)
175+
if (this.isRealTime() && this.rows && this.rows.length) {
176+
var row = this.rows[ this.rows.length - 1 ];
177+
if (row.date < time_now() - 600) {
178+
app.showMessage( 'warning', "This server has not submitted any data in over 10 minutes. It may have gone offline." );
179+
}
180+
}
173181
},
174182

175183
calcDataRange: function() {
@@ -260,21 +268,23 @@ Class.subclass( Page.Base, "Page.Server", {
260268

261269
// setup annotations
262270
var x_annos = [];
263-
alert_times.forEach( function(x) {
264-
x_annos.push({
265-
x: x,
266-
borderColor: '#888',
267-
yAxisIndex: 0,
268-
label: {
269-
show: true,
270-
text: 'Alert',
271-
style: {
272-
color: "#fff",
273-
background: '#f00'
271+
if (app.getPref('annotations') == '1') {
272+
alert_times.forEach( function(x) {
273+
x_annos.push({
274+
x: x,
275+
borderColor: '#888',
276+
yAxisIndex: 0,
277+
label: {
278+
show: true,
279+
text: 'Alert',
280+
style: {
281+
color: "#fff",
282+
background: '#f00'
283+
}
274284
}
275-
}
285+
});
276286
});
277-
});
287+
} // annotations enabled
278288

279289
// redraw graph series and annos
280290
var options = this.getGraphConfig(mon_id);

htdocs/js/pages/admin/Groups.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ Class.add( Page.Admin, {
5151
var self = this;
5252
html += this.getBasicTable( this.groups, cols, 'group', function(item, idx) {
5353
var actions = [];
54-
if (idx > 0) actions.push('<span class="link" onMouseUp="$P().move_up('+idx+')" title="Move Up"><i class="fa fa-arrow-up"></i></span>');
55-
if (idx < self.groups.length - 1) actions.push('<span class="link" onMouseUp="$P().move_down('+idx+')" title="Move Down"><i class="fa fa-arrow-down"></i></span>');
54+
if (idx > 0) actions.push('<span class="link" onMouseUp="$P().group_move_up('+idx+')" title="Move Up"><i class="fa fa-arrow-up"></i></span>');
55+
if (idx < self.groups.length - 1) actions.push('<span class="link" onMouseUp="$P().group_move_down('+idx+')" title="Move Down"><i class="fa fa-arrow-down"></i></span>');
5656
actions.push( '<span class="link" onMouseUp="$P().edit_group('+idx+')"><b>Edit</b></span>' );
5757
actions.push( '<span class="link" onMouseUp="$P().delete_group('+idx+')"><b>Delete</b></span>' );
5858

@@ -81,7 +81,7 @@ Class.add( Page.Admin, {
8181
this.div.html( html );
8282
},
8383

84-
move_up: function(idx) {
84+
group_move_up: function(idx) {
8585
// move selected item up (sort order change)
8686
var self = this;
8787
if (this.swap_in_progress) return;
@@ -103,7 +103,7 @@ Class.add( Page.Admin, {
103103
} );
104104
},
105105

106-
move_down: function(idx) {
106+
group_move_down: function(idx) {
107107
// move selected item down (sort order change)
108108
var self = this;
109109
if (this.swap_in_progress) return;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "performa",
3-
"version": "1.0.8",
3+
"version": "1.0.9",
44
"description": "A multi-server monitoring system with a web based UI.",
55
"author": "Joseph Huckaby <jhuckaby@gmail.com>",
66
"homepage": "https://github.com/jhuckaby/performa",

0 commit comments

Comments
 (0)