@cryptotaxi247 / netdata-1 / commits / b46af1c7b

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">&times;</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 });