basic health monitoring information is now rendered on the dashboard
Costa Tsaousis committed
Aug 26, 2016 at 00:44 UTC
b46af1c7be80e1a20a6583ff6666367934684fe7
6 files changed
+284
-35
src/health.c
+10
-7
@@ -1563,28 +1563,31 @@ static inline void health_rrdcalc2json_nolock(BUFFER *wb, RRDCALC *rc) {
1563
//
1564
//}
1565
1566
-void health_alarms2json(RRDHOST *host, BUFFER *wb) {
1566
+void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
1567
int i;
1568
rrdhost_rdlock(&localhost);
1569
1570
buffer_strcat(wb, "{\n\t\"alarms\": {\n");
1571
RRDCALC *rc;
1572
- for(i = 0, rc = host->alarms; rc ; rc = rc->next, i++) {
1573
- if(!rc->rrdset) continue;
1572
+ for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
1573
+ if(!rc->rrdset)
1574
+ continue;
1575
+
1576
+ if(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL))
1577
+ continue;
1578
1579
if(likely(i)) buffer_strcat(wb, ",\n");
1580
health_rrdcalc2json_nolock(wb, rc);
1581
+ i++;
1582
}
1583
1579
- buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
1584
+// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
1585
1586
// RRDCALCTEMPLATE *rt;
1587
// for(rt = host->templates; rt ; rt = rt->next)
1588
// health_rrdcalctemplate2json_nolock(wb, rt);
1589
1585
- buffer_strcat(wb, "\n\t}");
1586
- buffer_sprintf(wb, ",\n\t\"now\": %lu", (unsigned long)time(NULL));
1587
- buffer_strcat(wb, "\n}\n");
1590
+ buffer_sprintf(wb, "\n\t},\n\t\"now\": %lu\n}\n", (unsigned long)time(NULL));
1591
rrdhost_unlock(&localhost);
1592
}
1593
src/health.h
+1
-1
@@ -270,7 +270,7 @@ extern void *health_main(void *ptr);
270
extern void health_reload(void);
271
272
extern int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result);
273
-extern void health_alarms2json(RRDHOST *host, BUFFER *wb);
273
+extern void health_alarms2json(RRDHOST *host, BUFFER *wb, int all);
274
extern void health_alarm_log2json(RRDHOST *host, BUFFER *wb);
275
276
#endif //NETDATA_HEALTH_H
src/web_buffer_svg.c
+1
-1
@@ -1,7 +1,7 @@
1
#include "common.h"
2
3
#define BADGE_HORIZONTAL_PADDING 4
4
-#define VERDANA_KERNING 0.5
4
+#define VERDANA_KERNING 0.0
5
6
/*
7
* verdana11_widths[] has been generated with this method:
src/web_client.c
+23
-4
@@ -662,11 +662,19 @@ int web_client_api_request_v1_data_group(char *name, int def)
662
663
int web_client_api_request_v1_alarms(struct web_client *w, char *url)
664
{
665
- (void)url;
665
+ int all = 0;
666
+
667
+ while(url) {
668
+ char *value = mystrsep(&url, "?&[]");
669
+ if (!value || !*value) continue;
670
+
671
+ if(!strcmp(value, "all")) all = 1;
672
+ else if(!strcmp(value, "active")) all = 0;
673
+ }
674
675
buffer_flush(w->response.data);
676
w->response.data->contenttype = CT_APPLICATION_JSON;
669
- health_alarms2json(&localhost, w->response.data);
677
+ health_alarms2json(&localhost, w->response.data, all);
678
return 200;
679
}
680
@@ -737,6 +745,8 @@ cleanup:
745
}
746
747
int web_client_api_request_v1_badge(struct web_client *w, char *url) {
748
+ char buf[100 + 1];
749
+
750
int ret = 400;
751
buffer_flush(w->response.data);
752
@@ -851,8 +861,15 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
861
}
862
863
if(!label) {
854
- if(alarm)
855
- label = alarm;
864
+ if(alarm) {
865
+ snprintfz(buf, 100, "%s%s%s", (rc->rrdset)?rc->rrdset->family:"", (rc->rrdset)?": ":"", rc->name);
866
+ char *s = buf;
867
+ while(*s) {
868
+ if(*s == '_') *s = ' ';
869
+ s++;
870
+ }
871
+ label = buf;
872
+ }
873
else if(dimensions) {
874
const char *dim = buffer_tostring(dimensions);
875
if(*dim == '|') dim++;
@@ -864,6 +881,8 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
881
if(!units) {
882
if(options & RRDR_OPTION_PERCENTAGE)
883
units="%";
884
+ else if(alarm && rc && rc->calculation)
885
+ units = "";
886
else
887
units = st->units;
888
}
web/dashboard.js
+106
-6
@@ -16,6 +16,7 @@
16
// var netdataRegistryCallback = null; // Callback function that will be invoked with one param,
17
// the URLs from the registry
18
// var netdataShowHelp = true; // enable/disable help
19
+// var netdataShowAlarms = true; // enable/disable help
20
//
21
// You can also set the default netdata server, using the following.
22
// When this variable is not set, we assume the page is hosted on your
@@ -157,6 +158,9 @@
158
if(typeof netdataShowHelp === 'undefined')
159
netdataShowHelp = true;
160
161
+ if(typeof netdataShowAlarms === 'undefined')
162
+ netdataShowAlarms = true;
163
+
164
NETDATA.colors = NETDATA.themes.current.colors;
165
166
// these are the colors Google Charts are using
@@ -473,6 +477,8 @@
477
// console.log('onscroll');
478
479
NETDATA.options.last_page_scroll = new Date().getTime();
480
+ NETDATA.options.auto_refresher_stop_until = 0;
481
+
482
if(NETDATA.options.targets === null) return;
483
484
// when the user scrolls he sees that we have
@@ -481,7 +487,16 @@
487
// the charts back to visible quickly
488
var targets = NETDATA.options.targets;
489
var len = targets.length;
484
- while(len--) targets[len].isVisible();
490
+ while(len--) {
491
+ if(targets[len]._updating === true) {
492
+ if (typeof targets[len].xhr !== 'undefined') {
493
+ targets[len].xhr.abort();
494
+ targets[len].running = false;
495
+ targets[len]._updating = false;
496
+ }
497
+ targets[len].isVisible();
498
+ }
499
+ }
500
};
501
502
window.onresize = NETDATA.onresize;
@@ -505,7 +520,9 @@
520
411: { message: "Netdata registry server send invalid response to DELETE ", alert: false },
521
412: { message: "Netdata registry DELETE failed", alert: false },
522
413: { message: "Netdata registry server send invalid response to SWITCH ", alert: false },
508
- 414: { message: "Netdata registry SWITCH failed", alert: false }
523
+ 414: { message: "Netdata registry SWITCH failed", alert: false },
524
+ 415: { message: "Netdata alarms download failed", alert: false },
525
+ 416: { message: "Netdata alarms log download failed", alert: false }
526
};
527
NETDATA.errorLast = {
528
code: 0,
@@ -2810,16 +2827,23 @@
2827
async: true,
2828
xhrFields: { withCredentials: true } // required for the cookie
2829
})
2813
- .success(function(data) {
2830
+ .done(function(data) {
2831
+ that.xhr = undefined;
2832
+
2833
if(that.debug === true)
2834
that.log('data received. updating chart.');
2835
2836
that.updateChartWithData(data);
2837
})
2819
- .fail(function() {
2820
- error('data download failed for url: ' + that.data_url);
2838
+ .fail(function(msg) {
2839
+ that.xhr = undefined;
2840
+
2841
+ if(msg.statusText !== 'abort')
2842
+ error('data download failed for url: ' + that.data_url);
2843
})
2844
.always(function() {
2845
+ that.xhr = undefined;
2846
+
2847
NETDATA.statistics.refreshes_active--;
2848
that._updating = false;
2849
if(typeof callback === 'function') callback();
@@ -3283,6 +3307,8 @@
3307
// the first set will be executed in parallel
3308
// the second will be given to NETDATA.chartRefresher_uninitialized()
3309
NETDATA.chartRefresher = function() {
3310
+ // console.log('auto-refresher...');
3311
+
3312
if(NETDATA.options.pause === true) {
3313
// console.log('auto-refresher is paused');
3314
setTimeout(NETDATA.chartRefresher,
@@ -3299,6 +3325,7 @@
3325
}
3326
3327
if(NETDATA.options.current.parallel_refresher === false) {
3328
+ // console.log('auto-refresher is calling chartRefresherNoParallel(0)');
3329
NETDATA.chartRefresherNoParallel(0);
3330
return;
3331
}
@@ -3306,6 +3333,7 @@
3333
if(NETDATA.options.updated_dom === true) {
3334
// the dom has been updated
3335
// get the dom parts again
3336
+ // console.log('auto-refresher is calling parseDom()');
3337
NETDATA.parseDom(NETDATA.chartRefresher);
3338
return;
3339
}
@@ -3333,11 +3361,15 @@
3361
}
3362
3363
if(parallel.length > 0) {
3364
+ // console.log('auto-refresher executing in parallel for ' + parallel.length.toString() + ' charts');
3365
// this will execute the jobs in parallel
3366
$(parallel).each(function() {
3367
this.autoRefresh();
3368
})
3369
}
3370
+ else {
3371
+ console.log('auto-refresher nothing to do');
3372
+ }
3373
3374
// run the next refresh iteration
3375
setTimeout(NETDATA.chartRefresher,
@@ -3407,8 +3439,12 @@
3439
3440
NETDATA.parseDom(NETDATA.chartRefresher);
3441
3442
+ // Alarms initialization
3443
+ if(netdataShowAlarms === true)
3444
+ setTimeout(NETDATA.alarms.init, 1000);
3445
+
3446
// Registry initialization
3411
- setTimeout(NETDATA.registry.init, 1000);
3447
+ setTimeout(NETDATA.registry.init, 1500);
3448
};
3449
3450
// ----------------------------------------------------------------------------------------------------------------
@@ -5528,6 +5564,70 @@
5564
};
5565
5566
5567
+ // ----------------------------------------------------------------------------------------------------------------
5568
+ // Registry of netdata hosts
5569
+
5570
+ NETDATA.alarms = {
5571
+ current: null,
5572
+ callback: null,
5573
+
5574
+ get: function(what, callback) {
5575
+ $.ajax({
5576
+ url: NETDATA.serverDefault + '/api/v1/alarms?' + what.toString(),
5577
+ async: true,
5578
+ cache: false,
5579
+ xhrFields: { withCredentials: true } // required for the cookie
5580
+ })
5581
+ .done(function(data) {
5582
+ if(typeof callback === 'function')
5583
+ callback(data);
5584
+ })
5585
+ .fail(function() {
5586
+ NETDATA.error(415, host);
5587
+
5588
+ if(typeof callback === 'function')
5589
+ callback(null);
5590
+ });
5591
+ },
5592
+
5593
+ update_forever: function() {
5594
+ NETDATA.alarms.get('active', function(data) {
5595
+ if(data !== null) {
5596
+ NETDATA.alarms.current = data;
5597
+
5598
+ if (typeof NETDATA.alarms.callback === 'function') {
5599
+ NETDATA.alarms.callback(data);
5600
+ }
5601
+ }
5602
+
5603
+ setTimeout(NETDATA.alarms.update_forever, 10000);
5604
+ });
5605
+ },
5606
+
5607
+ get_log: function(callback) {
5608
+ $.ajax({
5609
+ url: NETDATA.serverDefault + '/api/v1/alarm_log',
5610
+ async: true,
5611
+ cache: false,
5612
+ xhrFields: { withCredentials: true } // required for the cookie
5613
+ })
5614
+ .done(function(data) {
5615
+ if(typeof callback === 'function')
5616
+ callback(data);
5617
+ })
5618
+ .fail(function() {
5619
+ NETDATA.error(416, host);
5620
+
5621
+ if(typeof callback === 'function')
5622
+ callback(null);
5623
+ });
5624
+ },
5625
+
5626
+ init: function() {
5627
+ NETDATA.alarms.update_forever();
5628
+ }
5629
+ };
5630
+
5631
// ----------------------------------------------------------------------------------------------------------------
5632
// Registry of netdata hosts
5633
web/index.html
+143
-16
@@ -572,17 +572,19 @@
572
<span class="icon-bar"></span>
573
<span class="icon-bar"></span>
574
</button>
575
- <a href="/" class="navbar-brand" id="hostname">netdata</a>
575
+ <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
576
</div>
577
<nav class="collapse navbar-collapse navbar-right" role="navigation">
578
<ul class="nav navbar-nav">
579
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-cog"></i> settings</a></li>
580
- <li class="hidden-sm"><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
581
- <li class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal"><i class="fa fa-cloud-download"></i> update</a></li>
582
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
579
+ <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal" title="alarms"><i class="fa fa-bell"></i><span id="alarms_count_badge" class="badge"></span></a></li>
580
+ <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal" title="dashboard settings"><i class="fa fa-cog"></i></a></li>
581
+ <li class="hidden-sm"><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata community"><i class="fa fa-github"></i></a></li>
582
+ <li class="hidden-sm" id="updateButton"><a href="#" class="btn" data-toggle="modal" data-target="#updateModal" title="check for update"><i class="fa fa-cloud-download"></i><span id="update_badge" class="badge"></span></a></li>
583
+ <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal" title="dashboard help"><i class="fa fa-question-circle"></i></a></li>
584
<li class="dropdown hidden-md hidden-lg hidden-xs">
585
<a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">Menu <strong class="caret"></strong></a>
586
<ul class="dropdown-menu scrollable-menu inpagemenu" role="menu">
587
+ <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fa fa-cog"></i> alarms</a></li>
588
<li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-cog"></i> settings</a></li>
589
<li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
590
<li><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
@@ -846,6 +848,42 @@
848
</div>
849
</div>
850
851
+ <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
852
+ <div class="modal-dialog modal-lg" role="document">
853
+ <div class="modal-content">
854
+ <div class="modal-header">
855
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
856
+ <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
857
+ </div>
858
+ <div class="modal-body">
859
+ <!-- Nav tabs -->
860
+ <ul class="nav nav-tabs" role="tablist">
861
+ <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
862
+ <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
863
+ <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
864
+ </ul>
865
+
866
+ <!-- Tab panes -->
867
+ <div class="tab-content">
868
+ <div role="tabpanel" class="tab-pane active" id="alarms_active">
869
+ loading...
870
+ </div>
871
+ <div role="tabpanel" class="tab-pane" id="alarms_all">
872
+ loading...
873
+ </div>
874
+ <div role="tabpanel" class="tab-pane" id="alarms_log">
875
+ loading...
876
+ </div>
877
+ </div>
878
+ </div>
879
+ <div class="modal-footer">
880
+ <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
881
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
882
+ </div>
883
+ </div>
884
+ </div>
885
+ </div>
886
+
887
<div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
888
<div class="modal-dialog modal-lg" role="document">
889
<div class="modal-content">
@@ -2363,6 +2401,92 @@ function renderChartsAndMenu(data) {
2401
renderPage(menus, data);
2402
}
2403
2404
+function alarmsUpdateModal() {
2405
+ var active = '<h3>Raised Alarms</h3>';
2406
+ var all = '<h3>All Running Alarms</h3>';
2407
+ var log = '<h3>Alarm Log</h3>';
2408
+ var footer = '<hr/>These are <a href="https://github.com/firehol/netdata/wiki/Generating-Badges" target="_blank">netdata badges</a>. You can copy and paste their URLs to embed them in any web page. Their color indicates the state of the alarm: <b>red</b> is critical, <b>orange</b> is warning, <b>bright green</b> is ok, <b>light grey</b> is undefined (i.e. no data or no status), <b>black</b> is not initialized.';
2409
+
2410
+ NETDATA.alarms.get('all', function(data) {
2411
+ if(data === null) {
2412
+ document.getElementById('alarms_active').innerHTML =
2413
+ document.getElementById('alarms_all').innerHTML =
2414
+ document.getElementById('alarms_log').innerHTML =
2415
+ 'failed to load alarm data!';
2416
+ return;
2417
+ }
2418
+
2419
+ var now = new Date().getTime();
2420
+ var x;
2421
+ var count_active = 0;
2422
+ var count_all = 0;
2423
+ var count_log = 0;
2424
+ var families = {};
2425
+ for(x in data.alarms) {
2426
+ var alarm = data.alarms[x];
2427
+
2428
+ if(typeof families[alarm.family] === 'undefined')
2429
+ families[alarm.family] = new Array();
2430
+
2431
+ families[alarm.family].push(alarm);
2432
+ }
2433
+
2434
+ for(x in families) {
2435
+ var active_family_added = false;
2436
+ var all_family_added = false;
2437
+
2438
+ var arr = families[x];
2439
+ var c = arr.length;
2440
+ while(c--) {
2441
+ var alarm = arr[c];
2442
+ if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
2443
+ if(!active_family_added) {
2444
+ active_family_added = true;
2445
+ active += '<h4>' + x + '</h4>';
2446
+ }
2447
+ active += '<embed><img src="' + NETDATA.serverDefault + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto&_=' + now.toString()+ '"></img></embed><br/>';
2448
+ count_active++;
2449
+ }
2450
+
2451
+ if(!all_family_added) {
2452
+ all_family_added = true;
2453
+ all += '<h4>' + x + '</h4>';
2454
+ }
2455
+ all += '<embed><img src="' + NETDATA.serverDefault + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto&_=' + now.toString()+ '"></img></embed><br/>';
2456
+ count_all++;
2457
+ }
2458
+ }
2459
+
2460
+ if(!count_active)
2461
+ active += "<h4>Everything is normal. No raised alarms.</h4>";
2462
+ else
2463
+ active += footer;
2464
+
2465
+ if(!count_all)
2466
+ all += "<h4>No alarms are running in this system.</h4>";
2467
+ else
2468
+ all += footer;
2469
+
2470
+ if(!count_log)
2471
+ log += "<h4>No alarms have been logged in this system.</h4>";
2472
+
2473
+ document.getElementById('alarms_active').innerHTML = active;
2474
+ document.getElementById('alarms_all').innerHTML = all;
2475
+ document.getElementById('alarms_log').innerHTML = log;
2476
+ });
2477
+}
2478
+
2479
+function alarmsCallback(data) {
2480
+ var count = 0;
2481
+ for(x in data.alarms)
2482
+ count++;
2483
+
2484
+ if(count > 0)
2485
+ document.getElementById('alarms_count_badge').innerHTML = count.toString();
2486
+ else
2487
+ document.getElementById('alarms_count_badge').innerHTML = '';
2488
+}
2489
+
2490
function downloadAllCharts(netdata_url) {
2491
if(typeof netdata_url === 'undefined' || netdata_url === null)
2492
netdata_url = NETDATA.serverDefault;
@@ -2371,6 +2495,8 @@ function downloadAllCharts(netdata_url) {
2495
$("#loadOverlay").css("display","none");
2496
$("#loadOverlay").css("display","none");
2497
2498
+ NETDATA.alarms.callback = alarmsCallback;
2499
+
2500
// download all the charts the server knows
2501
NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2502
@@ -2453,7 +2579,6 @@ function checkForUpdate(callback) {
2579
return null;
2580
}
2581
2456
-var updateBlinkCounter = 0;
2582
function notifyForUpdate(force) {
2583
versionLog('<p>checking for updates...</p>');
2584
@@ -2494,16 +2619,7 @@ function notifyForUpdate(force) {
2619
2620
versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest version: ' + sha2.toString() + '</p><p><a href="' + compare + '" target="_blank">Click here for the changes log</a> since your installed version, and<br/><a href="https://github.com/firehol/netdata/wiki/Updating-Netdata" target="_blank">click here for directions on updating</a> your netdata installation.</p><p>We suggest to review the changes log for new features you may be interested, or important bug fixes you may need.<br/>Keeping your netdata updated, is generally a good idea.</p>');
2621
2497
- function updateButtonBlink() {
2498
- updateBlinkCounter--;
2499
- if(updateBlinkCounter > 0)
2500
- $('#updateButton').fadeOut(500).fadeIn(500, updateButtonBlink);
2501
- }
2502
-
2503
- if(updateBlinkCounter === 0) {
2504
- updateBlinkCounter = 300;
2505
- updateButtonBlink();
2506
- }
2622
+ document.getElementById('update_badge').innerHTML = '!';
2623
}
2624
2625
if(save)
@@ -2772,6 +2888,17 @@ function finalizePage() {
2888
notifyForUpdate(true);
2889
});
2890
2891
+ $('#alarmsModal').on('shown.bs.modal', function() {
2892
+ alarmsUpdateModal();
2893
+ });
2894
+
2895
+ $('#alarmsModal').on('hidden.bs.modal', function() {
2896
+ document.getElementById('alarms_active').innerHTML =
2897
+ document.getElementById('alarms_all').innerHTML =
2898
+ document.getElementById('alarms_log').innerHTML =
2899
+ 'loading...';
2900
+ });
2901
+
2902
$('#deleteRegistryModal').on('hidden.bs.modal', function() {
2903
deleteRegistryGuid = null;
2904
});