summaryrefslogtreecommitdiffstats
path: root/web/dashboard.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/dashboard.js')
-rw-r--r--web/dashboard.js530
1 files changed, 459 insertions, 71 deletions
diff --git a/web/dashboard.js b/web/dashboard.js
index 67fb00b8b..4dd86391b 100644
--- a/web/dashboard.js
+++ b/web/dashboard.js
@@ -12,11 +12,17 @@
// var netdataNoBootstrap = true; // do not load bootstrap
// var netdataDontStart = true; // do not start the thread to process the charts
// var netdataErrorCallback = null; // Callback function that will be invoked upon error
-// var netdataNoRegistry = true; // Don't update the registry for this access
+// var netdataRegistry = true; // Update the registry (default disabled)
// 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
+// var netdataShowHelp = false; // enable/disable help (default enabled)
+// var netdataShowAlarms = true; // enable/disable alarms checks and notifications (default disabled)
+//
+// var netdataRegistryAfterMs = 1500 // the time to consult to registry on startup
+//
+// var netdataCallback = null; // a function to call when netdata is ready
+// // netdata will be running while this is called (call NETDATA.pause to stop it)
+// var netdataPrepCallback = null; // a callback to be called before netdata does anything else
//
// 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
@@ -50,6 +56,15 @@
// global namespace
var NETDATA = window.NETDATA || {};
+ NETDATA.name2id = function(s) {
+ return s
+ .replace(/ /g, '_')
+ .replace(/\(/g, '_')
+ .replace(/\)/g, '_')
+ .replace(/\./g, '_')
+ .replace(/\//g, '_');
+ };
+
// ----------------------------------------------------------------------------------------------------------------
// Detect the netdata server
@@ -93,25 +108,25 @@
// default URLs for all the external files we need
// make them RELATIVE so that the whole thing can also be
// installed under a web server
- NETDATA.jQuery = NETDATA.serverDefault + 'lib/jquery-1.12.0.min.js';
- NETDATA.peity_js = NETDATA.serverDefault + 'lib/jquery.peity.min.js';
- NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline.min.js';
- NETDATA.easypiechart_js = NETDATA.serverDefault + 'lib/jquery.easypiechart.min.js';
- NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge.min.js';
- NETDATA.dygraph_js = NETDATA.serverDefault + 'lib/dygraph-combined.js';
- NETDATA.dygraph_smooth_js = NETDATA.serverDefault + 'lib/dygraph-smooth-plotter.js';
- NETDATA.raphael_js = NETDATA.serverDefault + 'lib/raphael-min.js';
- NETDATA.morris_js = NETDATA.serverDefault + 'lib/morris.min.js';
- NETDATA.d3_js = NETDATA.serverDefault + 'lib/d3.min.js';
- NETDATA.c3_js = NETDATA.serverDefault + 'lib/c3.min.js';
- NETDATA.c3_css = NETDATA.serverDefault + 'css/c3.min.css';
- NETDATA.morris_css = NETDATA.serverDefault + 'css/morris.css';
+ NETDATA.jQuery = NETDATA.serverDefault + 'lib/jquery-2.2.4.min.js';
+ NETDATA.peity_js = NETDATA.serverDefault + 'lib/jquery.peity-3.2.0.min.js';
+ NETDATA.sparkline_js = NETDATA.serverDefault + 'lib/jquery.sparkline-2.1.2.min.js';
+ NETDATA.easypiechart_js = NETDATA.serverDefault + 'lib/jquery.easypiechart-97b5824.min.js';
+ NETDATA.gauge_js = NETDATA.serverDefault + 'lib/gauge-d5260c3.min.js';
+ NETDATA.dygraph_js = NETDATA.serverDefault + 'lib/dygraph-combined-dd74404.js';
+ NETDATA.dygraph_smooth_js = NETDATA.serverDefault + 'lib/dygraph-smooth-plotter-dd74404.js';
+ NETDATA.raphael_js = NETDATA.serverDefault + 'lib/raphael-2.2.4-min.js';
+ NETDATA.c3_js = NETDATA.serverDefault + 'lib/c3-0.4.11.min.js';
+ NETDATA.c3_css = NETDATA.serverDefault + 'css/c3-0.4.11.min.css';
+ NETDATA.d3_js = NETDATA.serverDefault + 'lib/d3-3.5.17.min.js';
+ NETDATA.morris_js = NETDATA.serverDefault + 'lib/morris-0.5.1.min.js';
+ NETDATA.morris_css = NETDATA.serverDefault + 'css/morris-0.5.1.css';
NETDATA.google_js = 'https://www.google.com/jsapi';
NETDATA.themes = {
white: {
- bootstrap_css: NETDATA.serverDefault + 'css/bootstrap.min.css',
- dashboard_css: NETDATA.serverDefault + 'dashboard.css',
+ bootstrap_css: NETDATA.serverDefault + 'css/bootstrap-3.3.7.min.css',
+ dashboard_css: NETDATA.serverDefault + 'dashboard.css?v20161002-1',
background: '#FFFFFF',
foreground: '#000000',
grid: '#DDDDDD',
@@ -127,12 +142,12 @@
gauge_gradient: false
},
slate: {
- bootstrap_css: NETDATA.serverDefault + 'css/bootstrap.slate.min.css',
- dashboard_css: NETDATA.serverDefault + 'dashboard.slate.css',
+ bootstrap_css: NETDATA.serverDefault + 'css/bootstrap.slate.min.css?v20161002-1',
+ dashboard_css: NETDATA.serverDefault + 'dashboard.slate.css?v20161002-1',
background: '#272b30',
foreground: '#C8C8C8',
- grid: '#373b40',
- axis: '#373b40',
+ grid: '#35393e',
+ axis: '#35393e',
/* colors: [ '#55bb33', '#ff2222', '#0099C6', '#faa11b', '#adbce0', '#DDDD00',
'#4178ba', '#f58122', '#a5cc39', '#f58667', '#f5ef89', '#cf93c0',
'#a5d18a', '#b8539d', '#3954a3', '#c8a9cf', '#c7de8a', '#fad20a',
@@ -155,12 +170,6 @@
else
NETDATA.themes.current = NETDATA.themes.white;
- 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
@@ -175,6 +184,25 @@
// (blue) (red) (orange) (green) (pink) (brown) (purple) (yellow) (gray)
//NETDATA.colors = [ '#5DA5DA', '#F15854', '#FAA43A', '#60BD68', '#F17CB0', '#B2912F', '#B276B2', '#DECF3F', '#4D4D4D' ];
+ if(typeof netdataShowHelp === 'undefined')
+ netdataShowHelp = true;
+
+ if(typeof netdataShowAlarms === 'undefined')
+ netdataShowAlarms = false;
+
+ if(typeof netdataRegistryAfterMs !== 'number' || netdataRegistryAfterMs < 0)
+ netdataRegistryAfterMs = 1500;
+
+ if(typeof netdataRegistry === 'undefined') {
+ // backward compatibility
+ if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry === false)
+ netdataRegistry = true;
+ else
+ netdataRegistry = false;
+ }
+ if(netdataRegistry === false && typeof netdataRegistryCallback === 'function')
+ netdataRegistry = true;
+
// ----------------------------------------------------------------------------------------------------------------
// the defaults for all charts
@@ -300,7 +328,9 @@
pan_and_zoom_factor_multiplier_shift: 3.0,
pan_and_zoom_factor_multiplier_alt: 4.0,
- abort_ajax_on_scroll: false,
+ abort_ajax_on_scroll: false, // kill pending ajax page scroll
+ async_on_scroll: false, // sync/async onscroll handler
+ onscroll_worker_duration_threshold: 30, // time in ms, to consider slow the onscroll handler
setOptionCallback: function() { ; }
},
@@ -475,21 +505,29 @@
NETDATA.onscroll();
};
- NETDATA.onscroll = function() {
- // console.log('onscroll');
-
- NETDATA.options.last_page_scroll = new Date().getTime();
- NETDATA.options.auto_refresher_stop_until = 0;
+ NETDATA.onscroll_updater_count = 0;
+ NETDATA.onscroll_updater_running = false;
+ NETDATA.onscroll_updater_last_run = 0;
+ NETDATA.onscroll_updater_watchdog = null;
+ NETDATA.onscroll_updater_max_duration = 0;
+ NETDATA.onscroll_updater_above_threshold_count = 0;
+ NETDATA.onscroll_updater = function() {
+ NETDATA.onscroll_updater_running = true;
+ NETDATA.onscroll_updater_count++;
+ var start = new Date().getTime();
- if(NETDATA.options.targets === null) return;
+ var targets = NETDATA.options.targets;
+ var len = targets.length;
// when the user scrolls he sees that we have
// hidden all the not-visible charts
// using this little function we try to switch
// the charts back to visible quickly
- var targets = NETDATA.options.targets;
- var len = targets.length;
+
+
if(NETDATA.options.abort_ajax_on_scroll === true) {
+ // we have to cancel pending requests too
+
while (len--) {
if (targets[len]._updating === true) {
if (typeof targets[len].xhr !== 'undefined') {
@@ -502,9 +540,69 @@
}
}
else {
+ // just find which chart is visible
+
while (len--)
targets[len].isVisible();
}
+
+ var end = new Date().getTime();
+ // console.log('scroll No ' + NETDATA.onscroll_updater_count + ' calculation took ' + (end - start).toString() + ' ms');
+
+ if(NETDATA.options.current.async_on_scroll === false) {
+ var dt = end - start;
+ if(dt > NETDATA.onscroll_updater_max_duration) {
+ // console.log('max onscroll event handler duration increased to ' + dt);
+ NETDATA.onscroll_updater_max_duration = dt;
+ }
+
+ if(dt > NETDATA.options.current.onscroll_worker_duration_threshold) {
+ // console.log('slow: ' + dt);
+ NETDATA.onscroll_updater_above_threshold_count++;
+
+ if(NETDATA.onscroll_updater_above_threshold_count > 2 && NETDATA.onscroll_updater_above_threshold_count * 100 / NETDATA.onscroll_updater_count > 2) {
+ NETDATA.setOption('async_on_scroll', true);
+ console.log('NETDATA: your browser is slow - enabling asynchronous onscroll event handler.');
+ }
+ }
+ }
+
+ NETDATA.onscroll_updater_last_run = start;
+ NETDATA.onscroll_updater_running = false;
+ };
+
+ NETDATA.onscroll = function() {
+ // console.log('onscroll');
+
+ NETDATA.options.last_page_scroll = new Date().getTime();
+ NETDATA.options.auto_refresher_stop_until = 0;
+
+ if(NETDATA.options.targets === null) return;
+
+ if(NETDATA.options.current.async_on_scroll === true) {
+ // async
+ if(NETDATA.onscroll_updater_running === false) {
+ NETDATA.onscroll_updater_running = true;
+ setTimeout(NETDATA.onscroll_updater, 0);
+ }
+ else {
+ if(NETDATA.onscroll_updater_watchdog !== null)
+ clearTimeout(NETDATA.onscroll_updater_watchdog);
+
+ NETDATA.onscroll_updater_watchdog = setTimeout(function() {
+ if(NETDATA.onscroll_updater_running === false && NETDATA.options.last_page_scroll > NETDATA.onscroll_updater_last_run) {
+ // console.log('watchdog');
+ NETDATA.onscroll_updater();
+ }
+
+ NETDATA.onscroll_updater_watchdog = null;
+ }, 200);
+ }
+ }
+ else {
+ // sync
+ NETDATA.onscroll_updater();
+ }
};
window.onresize = NETDATA.onresize;
@@ -530,7 +628,9 @@
413: { message: "Netdata registry server send invalid response to SWITCH ", 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 }
+ 416: { message: "Netdata alarms log download failed", alert: false },
+ 417: { message: "Netdata registry server send invalid response to SEARCH ", alert: false },
+ 418: { message: "Netdata registry SEARCH failed", alert: false }
};
NETDATA.errorLast = {
code: 0,
@@ -3448,11 +3548,13 @@
NETDATA.parseDom(NETDATA.chartRefresher);
// Alarms initialization
- if(netdataShowAlarms === true)
- setTimeout(NETDATA.alarms.init, 1000);
+ setTimeout(NETDATA.alarms.init, 1000);
// Registry initialization
- setTimeout(NETDATA.registry.init, 1500);
+ setTimeout(NETDATA.registry.init, netdataRegistryAfterMs);
+
+ if(typeof netdataCallback === 'function')
+ netdataCallback();
};
// ----------------------------------------------------------------------------------------------------------------
@@ -3857,7 +3959,7 @@
showLabelsOnHighlight: self.data('dygraph-showlabelsonhighlight') || true,
hideOverlayOnMouseOut: self.data('dygraph-hideoverlayonmouseout') || true,
- includeZero: self.data('dygraph-includezero') || false,
+ includeZero: self.data('dygraph-includezero') || ((chart_type === 'stacked')? true : false),
xRangePad: self.data('dygraph-xrangepad') || 0,
yRangePad: self.data('dygraph-yrangepad') || 1,
@@ -3901,10 +4003,8 @@
axisLineWidth: self.data('dygraph-axislinewidth') || 0.3,
drawGrid: self.data('dygraph-drawgrid') || true,
- drawXGrid: self.data('dygraph-drawxgrid') || undefined,
- drawYGrid: self.data('dygraph-drawygrid') || undefined,
gridLinePattern: self.data('dygraph-gridlinepattern') || null,
- gridLineWidth: self.data('dygraph-gridlinewidth') || 0.3,
+ gridLineWidth: self.data('dygraph-gridlinewidth') || 0.4,
gridLineColor: self.data('dygraph-gridlinecolor') || NETDATA.themes.current.grid,
maxNumberWidth: self.data('dygraph-maxnumberwidth') || 8,
@@ -4273,7 +4373,6 @@
state.dygraph_options.drawGrid = false;
state.dygraph_options.drawAxis = false;
state.dygraph_options.title = undefined;
- state.dygraph_options.units = undefined;
state.dygraph_options.ylabel = undefined;
state.dygraph_options.yLabelWidth = 0;
state.dygraph_options.labelsDivWidth = 120;
@@ -4961,6 +5060,7 @@
else if(typeof status === 'number')
speed = status;
+ // console.log('gauge speed ' + speed);
state.gauge_instance.animationSpeed = speed;
state.___gaugeOld__.speed = speed;
};
@@ -4994,6 +5094,7 @@
if(pcent > 100) pcent = 100;
state.gauge_instance.set(pcent);
+ // console.log('gauge set ' + pcent + ', value ' + value + ', min ' + min + ', max ' + max);
state.___gaugeOld__.value = value;
state.___gaugeOld__.min = min;
@@ -5476,7 +5577,8 @@
NETDATA.requiredJs = [
{
- url: NETDATA.serverDefault + 'lib/bootstrap.min.js',
+ url: NETDATA.serverDefault + 'lib/bootstrap-3.3.7.min.js',
+ async: false,
isAlreadyLoaded: function() {
// check if bootstrap is loaded
if(typeof $().emulateTransitionEnd == 'function')
@@ -5490,11 +5592,7 @@
}
},
{
- url: NETDATA.serverDefault + 'lib/jquery.nanoscroller.min.js',
- isAlreadyLoaded: function() { return false; }
- },
- {
- url: NETDATA.serverDefault + 'lib/bootstrap-toggle.min.js',
+ url: NETDATA.serverDefault + 'lib/jquery.nanoscroller-0.8.7.min.js',
isAlreadyLoaded: function() { return false; }
}
];
@@ -5510,27 +5608,25 @@
}
},
{
- url: NETDATA.serverDefault + 'css/font-awesome.min.css',
+ url: NETDATA.serverDefault + 'css/font-awesome.min.css?v4.6.3',
isAlreadyLoaded: function() { return false; }
},
{
url: NETDATA.themes.current.dashboard_css,
isAlreadyLoaded: function() { return false; }
- },
- {
- url: NETDATA.serverDefault + 'css/bootstrap-toggle.min.css',
- isAlreadyLoaded: function() { return false; }
}
];
+ NETDATA.loadedRequiredJs = 0;
NETDATA.loadRequiredJs = function(index, callback) {
- if(index >= NETDATA.requiredJs.length) {
+ if(index >= NETDATA.requiredJs.length) {
if(typeof callback === 'function')
callback();
return;
}
if(NETDATA.requiredJs[index].isAlreadyLoaded()) {
+ NETDATA.loadedRequiredJs++;
NETDATA.loadRequiredJs(++index, callback);
return;
}
@@ -5538,21 +5634,32 @@
if(NETDATA.options.debug.main_loop === true)
console.log('loading ' + NETDATA.requiredJs[index].url);
+ var async = true;
+ if(typeof NETDATA.requiredJs[index].async !== 'undefined' && NETDATA.requiredJs[index].async === false)
+ async = false;
+
$.ajax({
url: NETDATA.requiredJs[index].url,
cache: true,
dataType: "script",
xhrFields: { withCredentials: true } // required for the cookie
})
- .success(function() {
+ .done(function() {
if(NETDATA.options.debug.main_loop === true)
console.log('loaded ' + NETDATA.requiredJs[index].url);
-
- NETDATA.loadRequiredJs(++index, callback);
})
.fail(function() {
alert('Cannot load required JS library: ' + NETDATA.requiredJs[index].url);
})
+ .always(function() {
+ NETDATA.loadedRequiredJs++;
+
+ if(async === false)
+ NETDATA.loadRequiredJs(++index, callback);
+ })
+
+ if(async === true)
+ NETDATA.loadRequiredJs(++index, callback);
};
NETDATA.loadRequiredCSS = function(index) {
@@ -5576,22 +5683,248 @@
// Registry of netdata hosts
NETDATA.alarms = {
- current: null,
- callback: null,
+ onclick: null, // the callback to handle the click - it will be called with the alarm log entry
+ chart_div_offset: 100, // give that space above the chart when scrolling to it
+ chart_div_id_prefix: 'chart_', // the chart DIV IDs have this prefix (they should be NETDATA.name2id(chart.id))
+ chart_div_animation_duration: 0,// the duration of the animation while scrolling to a chart
+
+ ms_penalty: 0, // the time penalty of the next alarm
+ ms_between_notifications: 500, // firefox moves the alarms off-screen (above, outside the top of the screen)
+ // if alarms are shown faster than: one per 500ms
+
+ notifications: false, // when true, the browser supports notifications (may not be granted though)
+ last_notification_id: 0, // the id of the last alarm_log we have raised an alarm for
+ first_notification_id: 0, // the id of the first alarm_log entry for this session
+ // this is used to prevent CLEAR notifications for past events
+ // notifications_shown: new Array(),
+
+ server: null, // the server to connect to for fetching alarms
+ current: null, // the list of raised alarms - updated in the background
+ callback: null, // a callback function to call every time the list of raised alarms is refreshed
+
+ notify: function(entry) {
+ // console.log('alarm ' + entry.unique_id);
+
+ if(entry.updated === true) {
+ // console.log('alarm ' + entry.unique_id + ' has been updated by another alarm');
+ return;
+ }
+
+ var value = entry.value;
+ if(NETDATA.alarms.current !== null) {
+ var t = NETDATA.alarms.current.alarms[entry.chart + '.' + entry.name];
+ if(typeof t !== 'undefined' && entry.status == t.status)
+ value = t.value;
+ }
+
+ var name = entry.name.replace(/_/g, ' ');
+ var status = entry.status.toLowerCase();
+ var title = name + ' = ' + ((value === null)?'NaN':Math.floor(value)).toString() + ' ' + entry.units;
+ var tag = entry.alarm_id;
+ var icon = 'images/seo-performance-128.png';
+ var interaction = false;
+ var data = entry;
+ var show = true;
+
+ // console.log('alarm ' + entry.unique_id + ' ' + entry.chart + '.' + entry.name + ' is ' + entry.status);
+
+ switch(entry.status) {
+ case 'REMOVED':
+ show = false;
+ break;
+
+ case 'UNDEFINED':
+ return;
+
+ case 'UNINITIALIZED':
+ return;
+
+ case 'CLEAR':
+ if(entry.unique_id < NETDATA.alarms.first_notification_id) {
+ // console.log('alarm ' + entry.unique_id + ' is not current');
+ return;
+ }
+ if(entry.old_status === 'UNINITIALIZED' || entry.old_status === 'UNDEFINED') {
+ // console.log('alarm' + entry.unique_id + ' switch to CLEAR from ' + entry.old_status);
+ return;
+ }
+ title = name + ' back to normal';
+ icon = 'images/check-mark-2-128-green.png'
+ interaction = false;
+ break;
+
+ case 'WARNING':
+ if(entry.old_status === 'CRITICAL')
+ status = 'demoted to ' + entry.status.toLowerCase();
+
+ icon = 'images/alert-128-orange.png';
+ interaction = false;
+ break;
+
+ case 'CRITICAL':
+ if(entry.old_status === 'WARNING')
+ status = 'escalated to ' + entry.status.toLowerCase();
+
+ icon = 'images/alert-128-red.png'
+ interaction = true;
+ break;
+
+ default:
+ console.log('invalid alarm status ' + entry.status);
+ return;
+ }
+
+ /*
+ // cleanup old notifications with the same alarm_id as this one
+ // FIXME: it does not seem to work on any web browser!
+ var len = NETDATA.alarms.notifications_shown.length;
+ while(len--) {
+ var n = NETDATA.alarms.notifications_shown[len];
+ if(n.data.alarm_id === entry.alarm_id) {
+ console.log('removing old alarm ' + n.data.unique_id);
+
+ // close the notification
+ n.close.bind(n);
+
+ // remove it from the array
+ NETDATA.alarms.notifications_shown.splice(len, 1);
+ len = NETDATA.alarms.notifications_shown.length;
+ }
+ }
+ */
+
+ if(show === true) {
+
+ setTimeout(function() {
+ // show this notification
+ // console.log('new notification: ' + title);
+ var n = new Notification(title, {
+ body: entry.hostname + ' - ' + entry.chart + ' (' + entry.family + ') - ' + status + ': ' + entry.info,
+ tag: tag,
+ requireInteraction: interaction,
+ icon: NETDATA.serverDefault + icon,
+ data: data
+ });
+
+ n.onclick = function(event) {
+ event.preventDefault();
+ NETDATA.alarms.onclick(event.target.data);
+ };
+
+ // console.log(n);
+ // NETDATA.alarms.notifications_shown.push(n);
+ // console.log(entry);
+ }, NETDATA.alarms.ms_penalty);
+
+ NETDATA.alarms.ms_penalty += NETDATA.alarms.ms_between_notifications;
+ }
+ },
+
+ scrollToChart: function(chart_id) {
+ if(typeof chart_id === 'string') {
+ var offset = $('#' + NETDATA.alarms.chart_div_id_prefix + NETDATA.name2id(chart_id)).offset();
+ if(typeof offset !== 'undefined') {
+ $('html, body').animate({ scrollTop: offset.top - NETDATA.alarms.chart_div_offset }, NETDATA.alarms.chart_div_animation_duration);
+ return true;
+ }
+ }
+ return false;
+ },
+
+ scrollToAlarm: function(alarm) {
+ if(typeof alarm === 'object') {
+ var ret = NETDATA.alarms.scrollToChart(alarm.chart);
+
+ if(ret === true && NETDATA.options.page_is_visible === false)
+ window.focus();
+ // alert('netdata dashboard will now scroll to chart: ' + alarm.chart + '\n\nThis alarm opened to bring the browser window in front of the screen. Click on the dashboard to prevent it from appearing again.');
+ }
+
+ },
+
+ notifyAll: function() {
+ // console.log('FETCHING ALARM LOG');
+ NETDATA.alarms.get_log(NETDATA.alarms.last_notification_id, function(data) {
+ // console.log('ALARM LOG FETCHED');
+
+ if(data === null || typeof data !== 'object') {
+ console.log('invalid alarms log response');
+ return;
+ }
+
+ if(data.length === 0) {
+ console.log('received empty alarm log');
+ return;
+ }
+
+ // console.log('received alarm log of ' + data.length + ' entries, from ' + data[data.length - 1].unique_id.toString() + ' to ' + data[0].unique_id.toString());
+
+ data.sort(function(a, b) {
+ if(a.unique_id > b.unique_id) return -1;
+ if(a.unique_id < b.unique_id) return 1;
+ return 0;
+ });
+
+ NETDATA.alarms.ms_penalty = 0;
+
+ var len = data.length;
+ while(len--) {
+ if(data[len].unique_id > NETDATA.alarms.last_notification_id) {
+ NETDATA.alarms.notify(data[len]);
+ }
+ //else
+ // console.log('ignoring alarm (older) with id ' + data[len].unique_id.toString());
+ }
+
+ NETDATA.alarms.last_notification_id = data[0].unique_id;
+ NETDATA.localStorageSet('last_notification_id', NETDATA.alarms.last_notification_id, null);
+ // console.log('last notification id = ' + NETDATA.alarms.last_notification_id);
+ })
+ },
+
+ check_notifications: function() {
+ // returns true if we should fire 1+ notifications
+
+ if(NETDATA.alarms.notifications !== true) {
+ // console.log('notifications not available');
+ return false;
+ }
+
+ if(Notification.permission !== 'granted') {
+ // console.log('notifications not granted');
+ return false;
+ }
+
+ if(typeof NETDATA.alarms.current !== 'undefined' && typeof NETDATA.alarms.current.alarms === 'object') {
+ // console.log('can do alarms: old id = ' + NETDATA.alarms.last_notification_id + ' new id = ' + NETDATA.alarms.current.latest_alarm_log_unique_id);
+
+ if(NETDATA.alarms.current.latest_alarm_log_unique_id > NETDATA.alarms.last_notification_id) {
+ // console.log('new alarms detected');
+ return true;
+ }
+ //else console.log('no new alarms');
+ }
+ // else console.log('cannot process alarms');
+
+ return false;
+ },
get: function(what, callback) {
$.ajax({
- url: NETDATA.serverDefault + '/api/v1/alarms?' + what.toString(),
+ url: NETDATA.alarms.server + '/api/v1/alarms?' + what.toString(),
async: true,
cache: false,
xhrFields: { withCredentials: true } // required for the cookie
})
.done(function(data) {
+ if(NETDATA.alarms.first_notification_id === 0 && typeof data.latest_alarm_log_unique_id === 'number')
+ NETDATA.alarms.first_notification_id = data.latest_alarm_log_unique_id;
+
if(typeof callback === 'function')
callback(data);
})
.fail(function() {
- NETDATA.error(415, host);
+ NETDATA.error(415, NETDATA.alarms.server);
if(typeof callback === 'function')
callback(null);
@@ -5603,18 +5936,26 @@
if(data !== null) {
NETDATA.alarms.current = data;
+ if(NETDATA.alarms.check_notifications() === true) {
+ NETDATA.alarms.notifyAll();
+ }
+
if (typeof NETDATA.alarms.callback === 'function') {
NETDATA.alarms.callback(data);
}
+
+ // Health monitoring is disabled on this netdata
+ if(data.status === false) return;
}
setTimeout(NETDATA.alarms.update_forever, 10000);
});
},
- get_log: function(callback) {
+ get_log: function(last_id, callback) {
+ // console.log('fetching all log after ' + last_id.toString());
$.ajax({
- url: NETDATA.serverDefault + '/api/v1/alarm_log',
+ url: NETDATA.alarms.server + '/api/v1/alarm_log?after=' + last_id.toString(),
async: true,
cache: false,
xhrFields: { withCredentials: true } // required for the cookie
@@ -5624,7 +5965,7 @@
callback(data);
})
.fail(function() {
- NETDATA.error(416, host);
+ NETDATA.error(416, NETDATA.alarms.server);
if(typeof callback === 'function')
callback(null);
@@ -5632,7 +5973,27 @@
},
init: function() {
- NETDATA.alarms.update_forever();
+ var host = NETDATA.serverDefault;
+ while(host.slice(-1) === '/')
+ host = host.substring(0, host.length - 1);
+ NETDATA.alarms.server = host;
+
+ NETDATA.alarms.last_notification_id = NETDATA.localStorageGet('last_notification_id', NETDATA.alarms.last_notification_id, null);
+
+ if(NETDATA.alarms.onclick === null)
+ NETDATA.alarms.onclick = NETDATA.alarms.scrollToAlarm;
+
+ if(netdataShowAlarms === true) {
+ NETDATA.alarms.update_forever();
+
+ if('Notification' in window) {
+ // console.log('notifications available');
+ NETDATA.alarms.notifications = true;
+
+ if(Notification.permission === 'default')
+ Notification.requestPermission();
+ }
+ }
}
};
@@ -5696,8 +6057,7 @@
},
init: function() {
- if(typeof netdataNoRegistry !== 'undefined' && netdataNoRegistry)
- return;
+ if(netdataRegistry !== true) return;
NETDATA.registry.hello(NETDATA.serverDefault, function(data) {
if(data) {
@@ -5816,6 +6176,31 @@
});
},
+ search: function(machine_guid, callback) {
+ // SEARCH for the URLs of a machine:
+ $.ajax({
+ url: NETDATA.registry.server + '/api/v1/registry?action=search&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&for=' + machine_guid,
+ async: true,
+ cache: false,
+ xhrFields: { withCredentials: true } // required for the cookie
+ })
+ .done(function(data) {
+ if(typeof data.status !== 'string' || data.status !== 'ok') {
+ NETDATA.error(417, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data));
+ data = null;
+ }
+
+ if(typeof callback === 'function')
+ callback(data);
+ })
+ .fail(function() {
+ NETDATA.error(418, NETDATA.registry.server);
+
+ if(typeof callback === 'function')
+ callback(null);
+ });
+ },
+
switch: function(new_person_guid, callback) {
// impersonate
$.ajax({
@@ -5845,6 +6230,9 @@
// ----------------------------------------------------------------------------------------------------------------
// Boot it!
+ if(typeof netdataPrepCallback === 'function')
+ netdataPrepCallback();
+
NETDATA.errorReset();
NETDATA.loadRequiredCSS(0);