//
//}
-void health_alarms2json(RRDHOST *host, BUFFER *wb) {
+void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
int i;
rrdhost_rdlock(&localhost);
buffer_strcat(wb, "{\n\t\"alarms\": {\n");
RRDCALC *rc;
- for(i = 0, rc = host->alarms; rc ; rc = rc->next, i++) {
- if(!rc->rrdset) continue;
+ for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
+ if(!rc->rrdset)
+ continue;
+
+ if(!all && !(rc->status == RRDCALC_STATUS_WARNING || rc->status == RRDCALC_STATUS_CRITICAL))
+ continue;
if(likely(i)) buffer_strcat(wb, ",\n");
health_rrdcalc2json_nolock(wb, rc);
+ i++;
}
- buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
+// buffer_strcat(wb, "\n\t},\n\t\"templates\": {");
// RRDCALCTEMPLATE *rt;
// for(rt = host->templates; rt ; rt = rt->next)
// health_rrdcalctemplate2json_nolock(wb, rt);
- buffer_strcat(wb, "\n\t}");
- buffer_sprintf(wb, ",\n\t\"now\": %lu", (unsigned long)time(NULL));
- buffer_strcat(wb, "\n}\n");
+ buffer_sprintf(wb, "\n\t},\n\t\"now\": %lu\n}\n", (unsigned long)time(NULL));
rrdhost_unlock(&localhost);
}
extern void health_reload(void);
extern int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result);
-extern void health_alarms2json(RRDHOST *host, BUFFER *wb);
+extern void health_alarms2json(RRDHOST *host, BUFFER *wb, int all);
extern void health_alarm_log2json(RRDHOST *host, BUFFER *wb);
#endif //NETDATA_HEALTH_H
#include "common.h"
#define BADGE_HORIZONTAL_PADDING 4
-#define VERDANA_KERNING 0.5
+#define VERDANA_KERNING 0.0
/*
* verdana11_widths[] has been generated with this method:
int web_client_api_request_v1_alarms(struct web_client *w, char *url)
{
- (void)url;
+ int all = 0;
+
+ while(url) {
+ char *value = mystrsep(&url, "?&[]");
+ if (!value || !*value) continue;
+
+ if(!strcmp(value, "all")) all = 1;
+ else if(!strcmp(value, "active")) all = 0;
+ }
buffer_flush(w->response.data);
w->response.data->contenttype = CT_APPLICATION_JSON;
- health_alarms2json(&localhost, w->response.data);
+ health_alarms2json(&localhost, w->response.data, all);
return 200;
}
}
int web_client_api_request_v1_badge(struct web_client *w, char *url) {
+ char buf[100 + 1];
+
int ret = 400;
buffer_flush(w->response.data);
}
if(!label) {
- if(alarm)
- label = alarm;
+ if(alarm) {
+ snprintfz(buf, 100, "%s%s%s", (rc->rrdset)?rc->rrdset->family:"", (rc->rrdset)?": ":"", rc->name);
+ char *s = buf;
+ while(*s) {
+ if(*s == '_') *s = ' ';
+ s++;
+ }
+ label = buf;
+ }
else if(dimensions) {
const char *dim = buffer_tostring(dimensions);
if(*dim == '|') dim++;
if(!units) {
if(options & RRDR_OPTION_PERCENTAGE)
units="%";
+ else if(alarm && rc && rc->calculation)
+ units = "";
else
units = st->units;
}
// var netdataRegistryCallback = null; // Callback function that will be invoked with one param,
// the URLs from the registry
// var netdataShowHelp = true; // enable/disable help
+// var netdataShowAlarms = true; // enable/disable help
//
// You can also set the default netdata server, using the following.
// When this variable is not set, we assume the page is hosted on your
if(typeof netdataShowHelp === 'undefined')
netdataShowHelp = true;
+ if(typeof netdataShowAlarms === 'undefined')
+ netdataShowAlarms = true;
+
NETDATA.colors = NETDATA.themes.current.colors;
// these are the colors Google Charts are using
// console.log('onscroll');
NETDATA.options.last_page_scroll = new Date().getTime();
+ NETDATA.options.auto_refresher_stop_until = 0;
+
if(NETDATA.options.targets === null) return;
// when the user scrolls he sees that we have
// the charts back to visible quickly
var targets = NETDATA.options.targets;
var len = targets.length;
- while(len--) targets[len].isVisible();
+ while(len--) {
+ if(targets[len]._updating === true) {
+ if (typeof targets[len].xhr !== 'undefined') {
+ targets[len].xhr.abort();
+ targets[len].running = false;
+ targets[len]._updating = false;
+ }
+ targets[len].isVisible();
+ }
+ }
};
window.onresize = NETDATA.onresize;
411: { message: "Netdata registry server send invalid response to DELETE ", alert: false },
412: { message: "Netdata registry DELETE failed", alert: false },
413: { message: "Netdata registry server send invalid response to SWITCH ", alert: false },
- 414: { message: "Netdata registry SWITCH failed", alert: false }
+ 414: { message: "Netdata registry SWITCH failed", alert: false },
+ 415: { message: "Netdata alarms download failed", alert: false },
+ 416: { message: "Netdata alarms log download failed", alert: false }
};
NETDATA.errorLast = {
code: 0,
async: true,
xhrFields: { withCredentials: true } // required for the cookie
})
- .success(function(data) {
+ .done(function(data) {
+ that.xhr = undefined;
+
if(that.debug === true)
that.log('data received. updating chart.');
that.updateChartWithData(data);
})
- .fail(function() {
- error('data download failed for url: ' + that.data_url);
+ .fail(function(msg) {
+ that.xhr = undefined;
+
+ if(msg.statusText !== 'abort')
+ error('data download failed for url: ' + that.data_url);
})
.always(function() {
+ that.xhr = undefined;
+
NETDATA.statistics.refreshes_active--;
that._updating = false;
if(typeof callback === 'function') callback();
// the first set will be executed in parallel
// the second will be given to NETDATA.chartRefresher_uninitialized()
NETDATA.chartRefresher = function() {
+ // console.log('auto-refresher...');
+
if(NETDATA.options.pause === true) {
// console.log('auto-refresher is paused');
setTimeout(NETDATA.chartRefresher,
}
if(NETDATA.options.current.parallel_refresher === false) {
+ // console.log('auto-refresher is calling chartRefresherNoParallel(0)');
NETDATA.chartRefresherNoParallel(0);
return;
}
if(NETDATA.options.updated_dom === true) {
// the dom has been updated
// get the dom parts again
+ // console.log('auto-refresher is calling parseDom()');
NETDATA.parseDom(NETDATA.chartRefresher);
return;
}
}
if(parallel.length > 0) {
+ // console.log('auto-refresher executing in parallel for ' + parallel.length.toString() + ' charts');
// this will execute the jobs in parallel
$(parallel).each(function() {
this.autoRefresh();
})
}
+ else {
+ console.log('auto-refresher nothing to do');
+ }
// run the next refresh iteration
setTimeout(NETDATA.chartRefresher,
NETDATA.parseDom(NETDATA.chartRefresher);
+ // Alarms initialization
+ if(netdataShowAlarms === true)
+ setTimeout(NETDATA.alarms.init, 1000);
+
// Registry initialization
- setTimeout(NETDATA.registry.init, 1000);
+ setTimeout(NETDATA.registry.init, 1500);
};
// ----------------------------------------------------------------------------------------------------------------
};
+ // ----------------------------------------------------------------------------------------------------------------
+ // Registry of netdata hosts
+
+ NETDATA.alarms = {
+ current: null,
+ callback: null,
+
+ get: function(what, callback) {
+ $.ajax({
+ url: NETDATA.serverDefault + '/api/v1/alarms?' + what.toString(),
+ async: true,
+ cache: false,
+ xhrFields: { withCredentials: true } // required for the cookie
+ })
+ .done(function(data) {
+ if(typeof callback === 'function')
+ callback(data);
+ })
+ .fail(function() {
+ NETDATA.error(415, host);
+
+ if(typeof callback === 'function')
+ callback(null);
+ });
+ },
+
+ update_forever: function() {
+ NETDATA.alarms.get('active', function(data) {
+ if(data !== null) {
+ NETDATA.alarms.current = data;
+
+ if (typeof NETDATA.alarms.callback === 'function') {
+ NETDATA.alarms.callback(data);
+ }
+ }
+
+ setTimeout(NETDATA.alarms.update_forever, 10000);
+ });
+ },
+
+ get_log: function(callback) {
+ $.ajax({
+ url: NETDATA.serverDefault + '/api/v1/alarm_log',
+ async: true,
+ cache: false,
+ xhrFields: { withCredentials: true } // required for the cookie
+ })
+ .done(function(data) {
+ if(typeof callback === 'function')
+ callback(data);
+ })
+ .fail(function() {
+ NETDATA.error(416, host);
+
+ if(typeof callback === 'function')
+ callback(null);
+ });
+ },
+
+ init: function() {
+ NETDATA.alarms.update_forever();
+ }
+ };
+
// ----------------------------------------------------------------------------------------------------------------
// Registry of netdata hosts
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
- <a href="/" class="navbar-brand" id="hostname">netdata</a>
+ <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
</div>
<nav class="collapse navbar-collapse navbar-right" role="navigation">
<ul class="nav navbar-nav">
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-cog"></i> settings</a></li>
- <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>
- <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>
- <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
<li class="dropdown hidden-md hidden-lg hidden-xs">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">Menu <strong class="caret"></strong></a>
<ul class="dropdown-menu scrollable-menu inpagemenu" role="menu">
+ <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal"><i class="fa fa-cog"></i> alarms</a></li>
<li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal"><i class="fa fa-cog"></i> settings</a></li>
<li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank"><i class="fa fa-github"></i> community</a></li>
<li><a href="#" class="btn" data-toggle="modal" data-target="#helpModal"><i class="fa fa-question-circle"></i> help</a></li>
</div>
</div>
+ <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
+ <div class="modal-dialog modal-lg" role="document">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
+ <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
+ </div>
+ <div class="modal-body">
+ <!-- Nav tabs -->
+ <ul class="nav nav-tabs" role="tablist">
+ <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
+ <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
+ <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
+ </ul>
+
+ <!-- Tab panes -->
+ <div class="tab-content">
+ <div role="tabpanel" class="tab-pane active" id="alarms_active">
+ loading...
+ </div>
+ <div role="tabpanel" class="tab-pane" id="alarms_all">
+ loading...
+ </div>
+ <div role="tabpanel" class="tab-pane" id="alarms_log">
+ loading...
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
<div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
renderPage(menus, data);
}
+function alarmsUpdateModal() {
+ var active = '<h3>Raised Alarms</h3>';
+ var all = '<h3>All Running Alarms</h3>';
+ var log = '<h3>Alarm Log</h3>';
+ 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.';
+
+ NETDATA.alarms.get('all', function(data) {
+ if(data === null) {
+ document.getElementById('alarms_active').innerHTML =
+ document.getElementById('alarms_all').innerHTML =
+ document.getElementById('alarms_log').innerHTML =
+ 'failed to load alarm data!';
+ return;
+ }
+
+ var now = new Date().getTime();
+ var x;
+ var count_active = 0;
+ var count_all = 0;
+ var count_log = 0;
+ var families = {};
+ for(x in data.alarms) {
+ var alarm = data.alarms[x];
+
+ if(typeof families[alarm.family] === 'undefined')
+ families[alarm.family] = new Array();
+
+ families[alarm.family].push(alarm);
+ }
+
+ for(x in families) {
+ var active_family_added = false;
+ var all_family_added = false;
+
+ var arr = families[x];
+ var c = arr.length;
+ while(c--) {
+ var alarm = arr[c];
+ if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
+ if(!active_family_added) {
+ active_family_added = true;
+ active += '<h4>' + x + '</h4>';
+ }
+ active += '<embed><img src="' + NETDATA.serverDefault + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto&_=' + now.toString()+ '"></img></embed><br/>';
+ count_active++;
+ }
+
+ if(!all_family_added) {
+ all_family_added = true;
+ all += '<h4>' + x + '</h4>';
+ }
+ all += '<embed><img src="' + NETDATA.serverDefault + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto&_=' + now.toString()+ '"></img></embed><br/>';
+ count_all++;
+ }
+ }
+
+ if(!count_active)
+ active += "<h4>Everything is normal. No raised alarms.</h4>";
+ else
+ active += footer;
+
+ if(!count_all)
+ all += "<h4>No alarms are running in this system.</h4>";
+ else
+ all += footer;
+
+ if(!count_log)
+ log += "<h4>No alarms have been logged in this system.</h4>";
+
+ document.getElementById('alarms_active').innerHTML = active;
+ document.getElementById('alarms_all').innerHTML = all;
+ document.getElementById('alarms_log').innerHTML = log;
+ });
+}
+
+function alarmsCallback(data) {
+ var count = 0;
+ for(x in data.alarms)
+ count++;
+
+ if(count > 0)
+ document.getElementById('alarms_count_badge').innerHTML = count.toString();
+ else
+ document.getElementById('alarms_count_badge').innerHTML = '';
+}
+
function downloadAllCharts(netdata_url) {
if(typeof netdata_url === 'undefined' || netdata_url === null)
netdata_url = NETDATA.serverDefault;
$("#loadOverlay").css("display","none");
$("#loadOverlay").css("display","none");
+ NETDATA.alarms.callback = alarmsCallback;
+
// download all the charts the server knows
NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
return null;
}
-var updateBlinkCounter = 0;
function notifyForUpdate(force) {
versionLog('<p>checking for updates...</p>');
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>');
- function updateButtonBlink() {
- updateBlinkCounter--;
- if(updateBlinkCounter > 0)
- $('#updateButton').fadeOut(500).fadeIn(500, updateButtonBlink);
- }
-
- if(updateBlinkCounter === 0) {
- updateBlinkCounter = 300;
- updateButtonBlink();
- }
+ document.getElementById('update_badge').innerHTML = '!';
}
if(save)
notifyForUpdate(true);
});
+ $('#alarmsModal').on('shown.bs.modal', function() {
+ alarmsUpdateModal();
+ });
+
+ $('#alarmsModal').on('hidden.bs.modal', function() {
+ document.getElementById('alarms_active').innerHTML =
+ document.getElementById('alarms_all').innerHTML =
+ document.getElementById('alarms_log').innerHTML =
+ 'loading...';
+ });
+
$('#deleteRegistryModal').on('hidden.bs.modal', function() {
deleteRegistryGuid = null;
});