4 <title>netdata dashboard</title>
5 <meta name="application-name" content="netdata">
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
9 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10 <meta name="viewport" content="width=device-width, initial-scale=1">
11 <meta name="apple-mobile-web-app-capable" content="yes">
12 <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
13 <meta name="author" content="costa@tsaousis.gr">
15 <!-- <link rel="shortcut icon" href="images/seo-performance-multi-size.ico"> -->
17 <!-- <link rel="apple-touch-icon" href="images/seo-performance-72.png"> -->
18 <!-- <link rel="apple-touch-icon" sizes="72x72" href="images/seo-performance-72.png"> -->
19 <!-- <link rel="apple-touch-icon" sizes="114x114" href="images/seo-performance-114.png"> -->
21 <!-- <link rel="icon" type="image/png" sizes="512x512" href="images/seo-performance-512.png"> -->
22 <!-- <link rel="icon" type="image/png" sizes="256x256" href="images/seo-performance-256.png"> -->
23 <!-- <link rel="icon" type="image/png" sizes="128x128" href="images/seo-performance-128.png"> -->
24 <!-- <link rel="icon" type="image/png" sizes="64x64" href="images/seo-performance-64.png"> -->
25 <!-- <link rel="icon" type="image/png" sizes="48x48" href="images/seo-performance-48.png"> -->
26 <!-- <link rel="icon" type="image/png" sizes="24x24" href="images/seo-performance-24.png"> -->
27 <!-- <link rel="icon" type="image/png" sizes="16x16" href="images/seo-performance-16.png"> -->
28 <!-- <link rel="icon" type="image/png" sizes="32x32" href="images/seo-performance-32.png"> -->
30 <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACNklEQVRYhcXXv2tUQRAH8M+FEIJISBHCIWIhIQSUILERi4AiiqCggiIiomAjlhaC4j+ghYWISgqNohZaCBZBC8Ei8QdEUCutFBsxCBqDYkgci/cunkfuJffjJQPD8mZm5/vd2WV2HzlJ0Bs8CvrywsgCHwy+BpGOg0sJfjj4nYKX9FdwKG9gwZlgtgK8pLOpPxfw1mCoCnClDgWtzQTvCEYWCV7SkWAlFBoEb8dlDKBF8t2bMWUSH/AHr3CiEfz5CPUusPJLkRCdk5ZqyeqUrQv4R7E5TwK7M3zTeIKduRAIitiWEfIY69GdCwGcRFuG/xqONRkzkaA7+J5x+MaDtWmHvJ4HgeEM8Nn0bridfv9HoOFyBAdwJCPkqqTzHWwUaz7wgeBHxupfBKuCj2W25mxBsCGYyAB/FxTT27HcPlyep64tCLbjKbqqhLzBlgKfF8pVE4FgRXABI+ioEnYfOyzcFWsCbg+OV+xlpU4ER4O+4HVwL51b3xYEXcGu4Ao+YQhr5gmdxHmsQyfG0b/YxbWmLfRWmnxa0s06VbTMCpnBS9zFzQKTwR5cXCzwHIE02Sl8wSZsRI/kgLVJqjSd+t9LVjiG1diPszhdK3A5gR48k5zYMTwscC59sfT799CYKvA8EttbSeXgTr3gJQKl91kR+yTlvyG5uUbLYh9gb+ovltkb6qYtNSRo3kOygsBSzGlKsubf43USWLYK5CLLXoFWyU/CtzLbVDpW2n+m40yN9ukqdvAX9ac/EIgOapcAAAAASUVORK5CYII=">
32 <meta property="og:locale" content="en_US" />
33 <meta property="og:url" content="https://my-netdata.io" />
34 <meta property="og:type" content="website" />
35 <meta property="og:site_name" content="netdata"/>
36 <meta property="og:title" content="Get control of your Linux Servers. Simple. Effective. Awesome." />
37 <meta property="og:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." />
38 <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/22945737/e98cd0c6-f2fd-11e6-96f1-5501934b0955.png" />
39 <meta property="og:image:type" content="image/png" />
40 <meta property="fb:app_id" content="1200089276712916" />
42 <meta name="twitter:card" content="summary" />
43 <meta name="twitter:site" content="@linuxnetdata" />
44 <meta name="twitter:title" content="Get control of your Linux Servers. Simple. Effective. Awesome." />
45 <meta name="twitter:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." />
46 <meta name="twitter:image" content="https://cloud.githubusercontent.com/assets/2662304/14092712/93b039ea-f551-11e5-822c-beadbf2b2a2e.gif" />
49 /* prevent body from hiding under the navbar */
62 font-family: sans-serif;
63 padding: 40vh 0 40vh 0;
68 .modal-wide .modal-dialog {
72 /* fix # anchors scrolling under the navbar
73 https://github.com/twbs/bootstrap/issues/1768#issuecomment-46519033
83 h1:before, h2:before {
123 /* fix the navbar shifting when a modal is open */
124 /* https://github.com/twbs/bootstrap/issues/14040#issuecomment-159891033 */
126 width: 100% !important;
127 padding-right: 0 !important;
128 /* overflow-y: scroll !important; */
129 /* position: fixed !important;*/
133 /* make accordion use the whole header bar for expand/collapse */
143 * Scrollspy and affixed enhanced navigation to highlight sections and secondary
144 * sections of docs content.
149 top: 70px !important;
158 max-height: calc(100% - 70px) !important;
160 /*width: 220px !important;*/
163 /* By default it's not affixed in mobile views, so undo that */
164 .dashboard-sidebar.affix {
168 @media (min-width: 768px) {
174 /* First level of nav */
180 /* All levels of nav */
181 .dashboard-sidebar .nav > li > a {
188 .dashboard-sidebar .nav > li > a > .fa {
192 .dashboard-sidebar .nav > li > a:hover,
193 .dashboard-sidebar .nav > li > a:focus {
196 text-decoration: none;
197 background-color: transparent;
198 border-left: 1px solid #563d7c;
200 .dashboard-sidebar .nav > .active > a,
201 .dashboard-sidebar .nav > .active:hover > a,
202 .dashboard-sidebar .nav > .active:focus > a {
206 background-color: transparent;
207 border-left: 2px solid #563d7c;
210 /* Nav: second level (shown on .active) */
211 .dashboard-sidebar .nav .nav {
212 display: none; /* Hide by default, but at >768px, show it */
213 padding-bottom: 10px;
215 .dashboard-sidebar .nav .nav > li > a {
222 .dashboard-sidebar .nav .nav > li > a:hover,
223 .dashboard-sidebar .nav .nav > li > a:focus {
226 .dashboard-sidebar .nav .nav > .active > a,
227 .dashboard-sidebar .nav .nav > .active:hover > a,
228 .dashboard-sidebar .nav .nav > .active:focus > a {
236 .dropdown-menu.columns-2 {
241 .dropdown-menu li a {
245 .dropdown-menu.multi-column {
248 .multi-column-dropdown {
252 .multi-column-dropdown li a {
255 line-height: 1.428571429;
258 .multi-column-dropdown li a:hover {
259 text-decoration: none;
261 background-color: #262626;
269 /* Back to top (hidden on mobile) */
271 .dashboard-theme-toggle {
281 .dashboard-theme-toggle:hover {
283 text-decoration: none;
285 .dashboard-theme-toggle {
290 width: calc(100% - 20px) !important;
294 display: inline-block;
303 @media (min-width: 768px) {
310 .dashboard-theme-toggle {
315 /* Show and affix the side nav when space allows it */
316 @media (min-width: 992px) {
318 padding-left: 0% !important;
322 width: calc(100% - 213px) !important;
323 padding-left: 1% !important;
324 padding-right: 0% !important;
328 display: inline-block !important;
329 width: 213px !important;
332 .dashboard-sidebar .nav > .active > ul {
336 /* Widen the fixed sidebar */
337 .dashboard-sidebar.affix,
338 .dashboard-sidebar.affix-top,
339 .dashboard-sidebar.affix-bottom {
340 width: 213px !important;
342 .dashboard-sidebar.affix {
343 position: fixed; /* Undo the static from mobile first approach */
346 .dashboard-sidebar.affix-bottom {
347 position: absolute; /* Undo the static from mobile first approach */
349 .dashboard-sidebar.affix-bottom .dashboard-sidenav,
350 .dashboard-sidebar.affix .dashboard-sidenav {
356 @media (min-width: 1200px) {
358 padding-left: 2% !important;
362 width: calc(100% - 233px) !important;
363 padding-left: 1% !important;
364 padding-right: 1% !important;
368 display: inline-block !important;
369 width: 233px !important;
372 /* Widen the fixed sidebar again */
373 .dashboard-sidebar.affix,
374 .dashboard-sidebar.affix-top,
375 .dashboard-sidebar.affix-bottom {
376 width: 233px !important;
380 @media (min-width: 1360px) {
382 padding-left: 3% !important;
386 width: calc(100% - 263px) !important;
387 padding-left: 1% !important;
388 padding-right: 2% !important;
392 display: inline-block !important;
393 width: 263px !important;
396 /* Widen the fixed sidebar again */
397 .dashboard-sidebar.affix,
398 .dashboard-sidebar.affix-top,
399 .dashboard-sidebar.affix-bottom {
400 width: 263px !important;
406 <!-- check which theme to use -->
407 <script type="text/javascript">
408 // enable alarms checking and notifications
409 var netdataShowAlarms = true;
411 // enable registry updates
412 var netdataRegistry = true;
414 // --------------------------------------------------------------------
421 update_always: false,
434 hasProperty: function(property) {
435 // console.log('checking property ' + property + ' of type ' + typeof(this[property]));
436 return typeof this[property] !== 'undefined';
439 genHash: function() {
440 var hash = urlOptions.hash;
442 if(urlOptions.pan_and_zoom === true) {
443 hash += ';after=' + urlOptions.after.toString() +
444 ';before=' + urlOptions.before.toString();
447 if(urlOptions.theme !== null)
448 hash += ';theme=' + urlOptions.theme.toString();
450 if(urlOptions.help !== null)
451 hash += ';help=' + urlOptions.help.toString();
453 if(urlOptions.update_always === true)
454 hash += ';update_always=true';
459 parseHash: function() {
460 var variables = document.location.hash.split(';');
461 var len = variables.length;
464 var p = variables[len].split('=');
465 if(urlOptions.hasProperty(p[0]) && typeof p[1] !== 'undefined')
466 urlOptions[p[0]] = decodeURIComponent(p[1]);
469 if(variables[len].length > 0)
470 urlOptions.hash = variables[len];
474 var booleans = [ 'nowelcome', 'show_alarms', 'pan_and_zoom', 'update_always' ];
475 len = booleans.length;
477 if(urlOptions[booleans[len]] === 'true' || urlOptions[booleans[len]] === true || urlOptions[booleans[len]] === '1' || urlOptions[booleans[len]] === 1)
478 urlOptions[booleans[len]] = true;
480 urlOptions[booleans[len]] = false;
483 if(urlOptions.before > 0 && urlOptions.after > 0) {
484 urlOptions.pan_and_zoom = true;
485 urlOptions.nowelcome = true;
488 urlOptions.pan_and_zoom = false;
490 // console.log(urlOptions);
493 hashUpdate: function() {
494 history.replaceState(null, '', urlOptions.genHash());
497 netdataPanAndZoomCallback: function(status, after, before) {
498 urlOptions.pan_and_zoom = status;
499 urlOptions.after = after;
500 urlOptions.before = before;
501 urlOptions.hashUpdate();
506 urlOptions.parseHash();
508 // --------------------------------------------------------------------
509 // check options that should be processed before loading netdata.js
511 var localStorageTested = -1;
512 function localStorageTest() {
513 if(localStorageTested !== -1)
514 return localStorageTested;
516 if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
519 localStorage.setItem(test, test);
520 localStorage.removeItem(test);
521 localStorageTested = true;
524 localStorageTested = false;
528 localStorageTested = false;
530 return localStorageTested;
533 function loadLocalStorage(name) {
537 if(localStorageTest() === true)
538 ret = localStorage.getItem(name);
542 if(typeof ret === 'undefined' || ret === null)
545 // console.log('loaded: ' + name.toString() + ' = ' + ret.toString());
550 function saveLocalStorage(name, value) {
551 // console.log('saving: ' + name.toString() + ' = ' + value.toString());
553 if(localStorageTest() === true) {
554 localStorage.setItem(name, value.toString());
563 function getTheme(def) {
564 var ret = loadLocalStorage('netdataTheme');
565 if(typeof ret === 'undefined' || ret === null || ret === 'undefined')
571 function setTheme(theme) {
572 if(theme === netdataTheme) return false;
573 return saveLocalStorage('netdataTheme', theme);
576 var netdataTheme = getTheme('slate');
577 var netdataShowHelp = true;
579 if(urlOptions.theme !== null) {
580 setTheme(urlOptions.theme);
581 netdataTheme = urlOptions.theme;
584 urlOptions.theme = netdataTheme;
586 if(urlOptions.help !== null) {
587 saveLocalStorage('options.show_help', urlOptions.help);
588 netdataShowHelp = urlOptions.help;
591 urlOptions.help = loadLocalStorage('options.show_help');
594 // --------------------------------------------------------------------
595 // registry call back to render my-netdata menu
597 var netdataRegistryCallback = function(machines_array) {
600 var found = 0, hosted = 0;
601 var len, i, url, hostname, icon;
603 if(options.hosts.length > 1) {
604 el += '<li><a href="#" onClick="return false;" style="color: #666;" target="_blank">databases available on this host</a></li>';
605 a1 += '<li><a href="#" onClick="return false;"><i class="fa fa-info-circle" aria-hidden="true" style="color: #666;"></i></a></li>';
607 var base = document.location.origin.toString() + document.location.pathname.toString();
608 if(base.endsWith("/host/" + options.hostname + "/"))
609 base = base.substring(0, base.length - ("/host/" + options.hostname + "/").toString().length);
611 if(base.endsWith("/"))
612 base = base.substring(0, base.length - 1);
615 len = options.hosts.length;
617 hostname = options.hosts[i].hostname;
623 url = base + "/host/" + hostname + "/";
624 icon = "window-restore";
627 el += '<li id="registry_server_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');">' + hostname + '</a></li>';
628 a1 += '<li id="registry_action_hosted_' + len.toString() + '"><a class="registry_link" href="' + url + '" onClick="return gotoHostedModalHandler(\'' + url + '\');"><i class="fa fa-' + icon + '" aria-hidden="true" style="color: #999;"></i></a></li>';
633 el += '<li role="separator" class="divider"></li>';
634 a1 += '<li role="separator" class="divider"></li>';
637 if(machines_array === null) {
638 var ret = loadLocalStorage("registryCallback");
639 if(typeof ret !== 'undefined' && ret !== null) {
640 machines_array = JSON.parse(ret);
641 console.log("failed to contact the registry - loaded registry data from browser local storage");
646 saveLocalStorage("registryCallback", JSON.stringify(machines_array));
648 var machines = machines_array.sort(function (a, b) {
649 if (a.name > b.name) return -1;
650 if (a.name < b.name) return 1;
654 len = machines.length;
656 var u = machines[len];
658 el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>';
659 a1 += '<li id="registry_action_' + u.guid + '"><a href="#" onclick="deleteRegistryModalHandler(\'' + u.guid + '\',\'' + u.name + '\',\'' + u.url + '\'); return false;"><i class="fa fa-trash-o" aria-hidden="true" style="color: #999;"></i></a></li>';
665 el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">your netdata server list is empty...</a></li>';
667 el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #666;" target="_blank">failed to contact the registry...</a></li>';
669 a1 += '<li><a href="#" onClick="return false;"> </a></li>';
671 el += '<li role="separator" class="divider"></li>' +
672 '<li><a href="//london.netdata.rocks/default.html">UK - London (DigitalOcean.com)</a></li>' +
673 '<li><a href="//newyork.netdata.rocks/default.html">US - New York (DigitalOcean.com)</a></li>' +
674 '<li><a href="//sanfrancisco.netdata.rocks/default.html">US - San Francisco (DigitalOcean.com)</a></li>' +
675 '<li><a href="//atlanta.netdata.rocks/default.html">US - Atlanta (CDN77.com)</a></li>' +
676 '<li><a href="//frankfurt.netdata.rocks/default.html">Germany - Frankfurt (DigitalOcean.com)</a></li>' +
677 '<li><a href="//toronto.netdata.rocks/default.html">Canada - Toronto (DigitalOcean.com)</a></li>' +
678 '<li><a href="//singapore.netdata.rocks/default.html">Japan - Singapore (DigitalOcean.com)</a></li>' +
679 '<li><a href="//bangalore.netdata.rocks/default.html">India - Bangalore (DigitalOcean.com)</a></li>';
680 a1 += '<li role="separator" class="divider"></li>' +
681 '<li><a href="#"> </a></li>' +
682 '<li><a href="#"> </a></li>'+
683 '<li><a href="#"> </a></li>'+
684 '<li><a href="#"> </a></li>'+
685 '<li><a href="#"> </a></li>'+
686 '<li><a href="#"> </a></li>'+
687 '<li><a href="#"> </a></li>'+
688 '<li><a href="#"> </a></li>';
691 el += '<li role="separator" class="divider"></li>';
692 a1 += '<li role="separator" class="divider"></li>';
694 el += '<li><a href="https://github.com/firehol/netdata/wiki/mynetdata-menu-item" style="color: #999;" target="_blank">What is this?</a></li>';
695 a1 += '<li><a href="#" style="color: #999;" onclick="switchRegistryModalHandler(); return false;"><i class="fa fa-sliders" aria-hidden="true" style="color: #999;"></i></a></li>'
697 document.getElementById('mynetdata_servers').innerHTML = el;
698 document.getElementById('mynetdata_servers2').innerHTML = el;
699 document.getElementById('mynetdata_actions1').innerHTML = a1;
704 var this_is_demo = null; // FIXME
706 if(this_is_demo !== null) return this_is_demo;
707 this_is_demo = false;
710 if(typeof document.location.hostname === 'string') {
711 if(document.location.hostname.endsWith('.my-netdata.io') ||
712 document.location.hostname.endsWith('.mynetdata.io') ||
713 document.location.hostname.endsWith('.netdata.rocks') ||
714 document.location.hostname.endsWith('.firehol.org') ||
715 document.location.hostname.endsWith('.netdata.online'))
723 function netdataURL(url) {
724 if(typeof url === 'undefined')
725 url = document.location.toString();
727 if(url.indexOf('#') !== -1)
728 url = url.substring(0, url.indexOf('#'));
730 var hash = urlOptions.genHash();
732 // console.log('netdataURL: ' + url + hash);
737 function netdataReload(url) {
738 document.location = netdataURL(url);
740 // since we play with hash
741 // this is needed to reload the page
745 function gotoHostedModalHandler(url) {
746 document.location = url + urlOptions.genHash();
750 var gotoServerValidateRemaining = 0;
751 var gotoServerMiddleClick = false;
752 var gotoServerStop = false;
753 function gotoServerValidateUrl(id, guid, url) {
755 var error = 'failed';
757 if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://'))
758 // we penalize https only if the current url is http
759 // to allow the user walk through all its servers.
762 else if(document.location.toString().startsWith('https://') && url.toString().startsWith('http://'))
763 error = 'can\'t check';
765 var finalURL = netdataURL(url);
767 setTimeout(function() {
768 document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + finalURL + '" target="_blank">' + url + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
770 NETDATA.registry.hello(url, function(data) {
771 if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid === guid) {
772 // console.log('OK ' + id + ' URL: ' + url);
773 document.getElementById(guid + '-' + id + '-status').innerHTML = "OK";
775 if(!gotoServerStop) {
776 gotoServerStop = true;
778 if(gotoServerMiddleClick) {
779 window.open(finalURL, '_blank');
780 gotoServerMiddleClick = false;
781 document.getElementById('gotoServerResponse').innerHTML = '<b>Opening new window to ' + NETDATA.registry.machines[guid].name + '<br/><a href="' + finalURL + '">' + url + '</a></b><br/>(check your pop-up blocker if it fails)';
784 document.getElementById('gotoServerResponse').innerHTML += 'found it! It is at:<br/><small>' + url + '</small>';
785 document.location = finalURL;
790 if(typeof data !== 'undefined' && data !== null && typeof data.machine_guid === 'string' && data.machine_guid !== guid)
791 error = 'wrong machine';
793 document.getElementById(guid + '-' + id + '-status').innerHTML = error;
794 gotoServerValidateRemaining--;
795 if(gotoServerValidateRemaining <= 0) {
796 gotoServerMiddleClick = false;
797 document.getElementById('gotoServerResponse').innerHTML = '<b>Sorry! I cannot find any operational URL for this server</b>';
801 }, (id * 50) + penaldy);
804 function gotoServerModalHandler(guid) {
805 // console.log('goto server: ' + guid);
807 gotoServerStop = false;
809 var len = NETDATA.registry.machines[guid].alternate_urls.length;
812 document.getElementById('gotoServerResponse').innerHTML = '';
813 document.getElementById('gotoServerList').innerHTML = '';
814 document.getElementById('gotoServerName').innerHTML = NETDATA.registry.machines[guid].name;
815 $('#gotoServerModal').modal('show');
817 gotoServerValidateRemaining = len;
819 var url = NETDATA.registry.machines[guid].alternate_urls[len];
821 gotoServerValidateUrl(count++, guid, url);
824 setTimeout(function() {
825 if(gotoServerStop === false) {
826 document.getElementById('gotoServerResponse').innerHTML = '<b>Added all the known URLs for this machine.</b>';
827 NETDATA.registry.search(guid, function(data) {
828 // console.log(data);
829 len = data.urls.length;
831 var url = data.urls[len][1];
833 if(typeof checked[url] === 'undefined') {
834 gotoServerValidateRemaining++;
836 gotoServerValidateUrl(count++, guid, url);
845 function gotoServerInit() {
846 $(".registry_link").on('click', function(e) {
849 gotoServerMiddleClick = true;
852 gotoServerMiddleClick = false;
859 function switchRegistryModalHandler() {
860 document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid;
861 document.getElementById('switchRegistryURL').innerHTML = NETDATA.registry.server;
862 document.getElementById('switchRegistryResponse').innerHTML = '';
863 $('#switchRegistryModal').modal('show');
866 function notifyForSwitchRegistry() {
867 var n = document.getElementById('switchRegistryPersonGUID').value;
869 if(n !== '' && n.length === 36) {
870 NETDATA.registry.switch(n, function(result) {
871 if(result !== null) {
872 $('#switchRegistryModal').modal('hide');
873 NETDATA.registry.init();
876 document.getElementById('switchRegistryResponse').innerHTML = "<b>Sorry! The registry rejected your request.</b>";
881 document.getElementById('switchRegistryResponse').innerHTML = "<b>The ID you have entered is not a GUID.</b>";
884 var deleteRegistryUrl = null;
885 function deleteRegistryModalHandler(guid, name, url) {
888 deleteRegistryUrl = url;
889 document.getElementById('deleteRegistryServerName').innerHTML = name;
890 document.getElementById('deleteRegistryServerName2').innerHTML = name;
891 document.getElementById('deleteRegistryServerURL').innerHTML = url;
892 document.getElementById('deleteRegistryResponse').innerHTML = '';
893 $('#deleteRegistryModal').modal('show');
896 function notifyForDeleteRegistry() {
897 if(deleteRegistryUrl) {
898 NETDATA.registry.delete(deleteRegistryUrl, function(result) {
899 if(result !== null) {
900 deleteRegistryUrl = null;
901 $('#deleteRegistryModal').modal('hide');
902 NETDATA.registry.init();
905 document.getElementById('deleteRegistryResponse').innerHTML = "<b>Sorry! this command was rejected by the registry server.</b>";
915 hostname: 'netdata_server', // will be overwritten by the netdata server
924 // chartsMinWidth: 1450,
928 function chartsPerRow(total) {
929 if(options.chartsPerRow === 0) {
931 //var width = Math.floor(total / options.chartsMinWidth);
932 //if(width === 0) width = 1;
935 else return options.chartsPerRow;
938 function prioritySort(a, b) {
939 if(a.priority < b.priority) return -1;
940 if(a.priority > b.priority) return 1;
941 if(a.name < b.name) return -1;
945 function sortObjectByPriority(object) {
949 for(var i in object) {
950 if(!object.hasOwnProperty(i)) continue;
952 if(typeof idx[i] === 'undefined') {
958 sorted.sort(function(a, b) {
959 if(idx[a].priority < idx[b].priority) return -1;
960 if(idx[a].priority > idx[b].priority) return 1;
969 // ----------------------------------------------------------------------------
970 // scroll to a section, without changing the browser history
972 function scrollToId(hash) {
973 if(hash && hash != '' && document.getElementById(hash) !== null) {
974 var offset = $('#' + hash).offset();
975 if(typeof offset !== 'undefined')
976 $('html, body').animate({ scrollTop: offset.top }, 0);
979 // we must return false to prevent the default action
983 // ----------------------------------------------------------------------------
985 var netdataDashboard = {
986 sparklines_registry: {},
993 // generate a sparkline
994 // used in the documentation
995 sparkline: function (prefix, chart, dimension, units, suffix) {
996 if(options.data === null || typeof options.data.charts === 'undefined')
999 if(typeof options.data.charts[chart] === 'undefined')
1002 if(typeof options.data.charts[chart].dimensions === 'undefined')
1005 if(typeof options.data.charts[chart].dimensions[dimension] === 'undefined')
1008 var key = chart + '.' + dimension;
1010 if(typeof units === 'undefined')
1013 if(typeof this.sparklines_registry[key] === 'undefined')
1014 this.sparklines_registry[key] = { count: 1 };
1016 this.sparklines_registry[key].count++;
1018 key = key + '.' + this.sparklines_registry[key].count;
1020 return prefix + '<div data-netdata="' + chart + '" data-after="-120" data-width="25%" data-height="15px" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dimensions="' + dimension + '" data-show-value-of-' + dimension + '-at="' + key + '"></div> (<span id="' + key + '" style="display: inline-block; min-width: 50px; text-align: right;">X</span>' + units + ')' + suffix;
1023 gaugeChart: function(title, width, dimensions, colors) {
1024 if(typeof colors === 'undefined')
1027 if(typeof dimensions === 'undefined')
1030 return '<div data-netdata="CHART_UNIQUE_ID"'
1031 + ' data-dimensions="' + dimensions + '"'
1032 + ' data-chart-library="gauge"'
1033 + ' data-gauge-adjust="width"'
1034 + ' data-title="' + title + '"'
1035 + ' data-width="' + width + '"'
1036 + ' data-before="0"'
1037 + ' data-after="-CHART_DURATION"'
1038 + ' data-points="CHART_DURATION"'
1039 + ' data-colors="' + colors + '"'
1040 + ' role="application"></div>';
1043 anyAttribute: function(obj, attr, key, def) {
1044 if(typeof(obj[key]) !== 'undefined') {
1045 var x = obj[key][attr];
1047 if(typeof(x) === 'undefined')
1050 if(typeof(x) === 'function') {
1051 return x(netdataDashboard.os);
1060 menuTitle: function(chart) {
1061 if(typeof chart.menu_pattern !== 'undefined') {
1062 return (this.anyAttribute(this.menu, 'title', chart.menu_pattern, chart.menu_pattern).toString()
1063 + ' ' + chart.type.slice(-(chart.type.length - chart.menu_pattern.length - 1)).toString()).replace(/_/g, ' ');
1066 return (this.anyAttribute(this.menu, 'title', chart.menu, chart.menu)).toString().replace(/_/g, ' ');
1069 menuIcon: function(chart) {
1070 if(typeof chart.menu_pattern !== 'undefined')
1071 return this.anyAttribute(this.menu, 'icon', chart.menu_pattern, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>').toString();
1073 return this.anyAttribute(this.menu, 'icon', chart.menu, '<i class="fa fa-puzzle-piece" aria-hidden="true"></i>');
1076 menuInfo: function(chart) {
1077 if(typeof chart.menu_pattern !== 'undefined')
1078 return this.anyAttribute(this.menu, 'info', chart.menu_pattern, null);
1080 return this.anyAttribute(this.menu, 'info', chart.menu, null);
1083 menuHeight: function(chart) {
1084 if(typeof chart.menu_pattern !== 'undefined')
1085 return this.anyAttribute(this.menu, 'height', chart.menu_pattern, 1.0);
1087 return this.anyAttribute(this.menu, 'height', chart.menu, 1.0);
1090 submenuTitle: function(menu, submenu) {
1091 var key = menu + '.' + submenu;
1092 // console.log(key);
1093 var title = this.anyAttribute(this.submenu, 'title', key, submenu).toString().replace(/_/g, ' ');
1094 if(title.length > 28) {
1095 var a = title.substring(0, 13);
1096 var b = title.substring(title.length - 12, title.length);
1097 return a + '...' + b;
1102 submenuInfo: function(menu, submenu) {
1103 var key = menu + '.' + submenu;
1104 return this.anyAttribute(this.submenu, 'info', key, null);
1107 submenuHeight: function(menu, submenu, relative) {
1108 var key = menu + '.' + submenu;
1109 return this.anyAttribute(this.submenu, 'height', key, 1.0) * relative;
1112 contextInfo: function(id) {
1113 var x = this.anyAttribute(this.context, 'info', id, null);
1116 return '<div class="chart-message netdata-chart-alignment" role="document">' + x + '</div>';
1121 contextValueRange: function(id) {
1122 if(typeof this.context[id] !== 'undefined' && typeof this.context[id].valueRange !== 'undefined')
1123 return this.context[id].valueRange;
1125 return '[null, null]';
1128 contextHeight: function(id, def) {
1129 if(typeof this.context[id] !== 'undefined' && typeof this.context[id].height !== 'undefined')
1130 return def * this.context[id].height;
1136 // ----------------------------------------------------------------------------
1138 // enrich the data structure returned by netdata
1139 // to reflect our menu system and content
1140 // FIXME: this is a shame - we should fix charts naming (issue #807)
1141 function enrichChartData(chart) {
1142 var parts = chart.type.split('_');
1153 chart.menu = chart.type;
1154 if(parts.length > 2 && parts[1] === 'cache')
1155 chart.menu_pattern = tmp + '_' + parts[1];
1159 chart.menu = chart.type;
1160 if(parts.length > 2 && parts[1] === 'rndc')
1161 chart.menu_pattern = tmp + '_' + parts[1];
1165 chart.menu = chart.type;
1166 if(chart.id.match(/.*[\._\/-:]qemu[\._\/-:]*/) || chart.id.match(/.*[\._\/-:]kvm[\._\/-:]*/))
1167 chart.menu_pattern = 'cgqemu';
1169 chart.menu_pattern = 'cgroup';
1173 chart.menu = chart.type;
1174 if(parts.length > 2 && parts[1] === 'dhcpd')
1175 chart.menu_pattern = tmp + '_' + parts[1];
1179 chart.menu = chart.type;
1180 if(parts.length > 3 && parts[1] === 'status' && parts[2] === 'log')
1181 chart.menu_pattern = tmp + '_' + parts[1];
1186 chart.menu = chart.type;
1187 if(parts.length > 2 && parts[1] === 'log')
1188 chart.menu_pattern = tmp + '_' + parts[1];
1209 chart.menu = chart.type;
1210 chart.menu_pattern = tmp;
1216 // find a name for this device from fireqos info
1217 // we strip '_(in|out)' or '(in|out)_'
1218 if(chart.context === 'tc.qos' && (typeof options.submenu_names[chart.family] === 'undefined' || options.submenu_names[chart.family] === chart.family)) {
1219 var n = chart.name.split('.')[1];
1220 if(n.endsWith('_in'))
1221 options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_in'));
1222 else if(n.endsWith('_out'))
1223 options.submenu_names[chart.family] = n.slice(0, n.lastIndexOf('_out'));
1224 else if(n.startsWith('in_'))
1225 options.submenu_names[chart.family] = n.slice(3, n.length);
1226 else if(n.startsWith('out_'))
1227 options.submenu_names[chart.family] = n.slice(4, n.length);
1229 options.submenu_names[chart.family] = n;
1232 // increase the priority of IFB devices
1233 // to have inbound appear before outbound
1234 if(chart.id.match(/.*-ifb$/))
1240 chart.menu = chart.type;
1244 chart.submenu = chart.family;
1247 // ----------------------------------------------------------------------------
1249 function headMain(os, charts, duration) {
1254 if(typeof charts['system.swap'] !== 'undefined')
1255 head += '<div style="margin-right: 10px;" data-netdata="system.swap"'
1256 + ' data-dimensions="used"'
1257 + ' data-append-options="percentage"'
1258 + ' data-chart-library="easypiechart"'
1259 + ' data-title="Used Swap"'
1261 + ' data-easypiechart-max-value="100"'
1262 + ' data-width="8%"'
1263 + ' data-before="0"'
1264 + ' data-after="-' + duration.toString() + '"'
1265 + ' data-points="' + duration.toString() + '"'
1266 + ' data-colors="#DD4400"'
1267 + ' role="application"></div>';
1269 if(typeof charts['system.io'] !== 'undefined') {
1270 head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1271 + ' data-dimensions="in"'
1272 + ' data-chart-library="easypiechart"'
1273 + ' data-title="Disk Read"'
1274 + ' data-width="10%"'
1275 + ' data-before="0"'
1276 + ' data-after="-' + duration.toString() + '"'
1277 + ' data-points="' + duration.toString() + '"'
1278 + ' role="application"></div>';
1280 head += '<div style="margin-right: 10px;" data-netdata="system.io"'
1281 + ' data-dimensions="out"'
1282 + ' data-chart-library="easypiechart"'
1283 + ' data-title="Disk Write"'
1284 + ' data-width="10%"'
1285 + ' data-before="0"'
1286 + ' data-after="-' + duration.toString() + '"'
1287 + ' data-points="' + duration.toString() + '"'
1288 + ' role="application"></div>';
1291 if(typeof charts['system.cpu'] !== 'undefined')
1292 head += '<div data-netdata="system.cpu"'
1293 + ' data-chart-library="gauge"'
1294 + ' data-title="CPU"'
1296 + ' data-gauge-max-value="100"'
1297 + ' data-width="18%"'
1298 + ' data-after="-' + duration.toString() + '"'
1299 + ' data-points="' + duration.toString() + '"'
1300 + ' data-colors="' + NETDATA.colors[12] + '"'
1301 + ' role="application"></div>';
1303 if(typeof charts['system.ipv4'] !== 'undefined') {
1304 head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1305 + ' data-dimensions="received"'
1306 + ' data-chart-library="easypiechart"'
1307 + ' data-title="IPv4 Inbound"'
1308 + ' data-width="10%"'
1309 + ' data-before="0"'
1310 + ' data-after="-' + duration.toString() + '"'
1311 + ' data-points="' + duration.toString() + '"'
1312 + ' role="application"></div>';
1314 head += '<div style="margin-right: 10px;" data-netdata="system.ipv4"'
1315 + ' data-dimensions="sent"'
1316 + ' data-chart-library="easypiechart"'
1317 + ' data-title="IPv4 Outbound"'
1318 + ' data-width="10%"'
1319 + ' data-before="0"'
1320 + ' data-after="-' + duration.toString() + '"'
1321 + ' data-points="' + duration.toString() + '"'
1322 + ' role="application"></div>';
1324 else if(typeof charts['system.ipv6'] !== 'undefined') {
1325 head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1326 + ' data-dimensions="received"'
1327 + ' data-chart-library="easypiechart"'
1328 + ' data-title="IPv6 Inbound"'
1329 + ' data-units="kbps"'
1330 + ' data-width="10%"'
1331 + ' data-before="0"'
1332 + ' data-after="-' + duration.toString() + '"'
1333 + ' data-points="' + duration.toString() + '"'
1334 + ' role="application"></div>';
1336 head += '<div style="margin-right: 10px;" data-netdata="system.ipv6"'
1337 + ' data-dimensions="sent"'
1338 + ' data-chart-library="easypiechart"'
1339 + ' data-title="IPv6 Outbound"'
1340 + ' data-units="kbps"'
1341 + ' data-width="10%"'
1342 + ' data-before="0"'
1343 + ' data-after="-' + duration.toString() + '"'
1344 + ' data-points="' + duration.toString() + '"'
1345 + ' role="application"></div>';
1348 if(typeof charts['system.ram'] !== 'undefined')
1349 head += '<div style="margin-right: 10px;" data-netdata="system.ram"'
1350 + ' data-dimensions="used|buffers|active|wired"' // active and wired are FreeBSD stats
1351 + ' data-append-options="percentage"'
1352 + ' data-chart-library="easypiechart"'
1353 + ' data-title="Used RAM"'
1355 + ' data-easypiechart-max-value="100"'
1356 + ' data-width="8%"'
1357 + ' data-after="-' + duration.toString() + '"'
1358 + ' data-points="' + duration.toString() + '"'
1359 + ' data-colors="' + NETDATA.colors[7] + '"'
1360 + ' role="application"></div>';
1365 function generateHeadCharts(type, chart, duration) {
1367 var hcharts = netdataDashboard.anyAttribute(netdataDashboard.context, type, chart.context, []);
1368 if(hcharts.length > 0) {
1369 var hi = 0, hlen = hcharts.length;
1371 if(typeof hcharts[hi] === 'function')
1372 head += hcharts[hi](netdataDashboard.os, chart.id).replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1374 head += hcharts[hi].replace('CHART_DURATION', duration.toString()).replace('CHART_UNIQUE_ID', chart.id);
1381 function renderPage(menus, data) {
1382 var div = document.getElementById('charts_div');
1383 var pcent_width = Math.floor(100 / chartsPerRow($(div).width()));
1385 // find the proper duration for per-second updates
1386 var duration = Math.round(($(div).width() * pcent_width / 100 * data.update_every / 3) / 60) * 60;
1388 var sidebar = '<ul class="nav dashboard-sidenav" data-spy="affix" id="sidebar_ul">';
1389 var mainhead = headMain(netdataDashboard.os, data.charts, duration);
1392 var main = sortObjectByPriority(menus);
1393 var i = 0, len = main.length;
1395 var menu = main[i++];
1397 // generate an entry at the main menu
1399 var menuid = NETDATA.name2id('menu_' + menu);
1400 sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].icon + ' ' + menus[menu].title + '</a><ul class="nav">';
1401 html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div role="document">';
1403 if(menus[menu].info !== null)
1404 html += menus[menu].info;
1406 // console.log(' >> ' + menu + ' (' + menus[menu].priority + '): ' + menus[menu].title);
1409 var mhead = '<div class="netdata-chart-row">' + mainhead;
1412 // sort the submenus of this menu
1413 var sub = sortObjectByPriority(menus[menu].submenus);
1414 var si = 0, slen = sub.length;
1416 var submenu = sub[si++];
1418 // generate an entry at the submenu
1419 var submenuid = NETDATA.name2id('menu_' + menu + '_submenu_' + submenu);
1420 sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
1421 shtml += '<div class="netdata-group-container" id="' + submenuid + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>';
1423 if(menus[menu].submenus[submenu].info !== null)
1424 shtml += '<div class="chart-message netdata-chart-alignment" role="document">' + menus[menu].submenus[submenu].info + '</div>';
1426 var head = '<div class="netdata-chart-row">';
1429 // console.log(' \------- ' + submenu + ' (' + menus[menu].submenus[submenu].priority + '): ' + menus[menu].submenus[submenu].title);
1431 // sort the charts in this submenu of this menu
1432 menus[menu].submenus[submenu].charts.sort(prioritySort);
1433 var ci = 0, clen = menus[menu].submenus[submenu].charts.length;
1435 var chart = menus[menu].submenus[submenu].charts[ci++];
1437 // generate the submenu heading charts
1438 mhead += generateHeadCharts('mainheads', chart, duration);
1439 head += generateHeadCharts('heads', chart, duration);
1441 // generate the chart
1442 chtml += netdataDashboard.contextInfo(chart.context) + '<div id="chart_' + NETDATA.name2id(chart.id) + '" data-netdata="' + chart.id + '"'
1443 + ' data-width="' + pcent_width.toString() + '%"'
1444 + ' data-height="' + netdataDashboard.contextHeight(chart.context, options.chartsHeight).toString() + 'px"'
1445 + ' data-dygraph-valuerange="' + netdataDashboard.contextValueRange(chart.context) + '"'
1446 + ' data-before="0"'
1447 + ' data-after="-' + duration.toString() + '"'
1448 + ' data-id="' + NETDATA.name2id(options.hostname + '/' + chart.id) + '"'
1449 + ' data-colors="' + netdataDashboard.anyAttribute(netdataDashboard.context, 'colors', chart.context, '') + '"'
1450 + ' role="application"></div>';
1452 // console.log(' \------- ' + chart.id + ' (' + chart.priority + '): ' + chart.context + ' height: ' + menus[menu].submenus[submenu].height);
1456 shtml += head + chtml + '</div>';
1460 sidebar += '</ul></li>';
1461 html += mhead + shtml + '</div></div><hr role="separator"/>';
1464 sidebar += '<li class="" style="padding-top:15px;"><a href="https://github.com/firehol/netdata/wiki/Add-more-charts-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more charts</a></li>';
1465 sidebar += '<li class=""><a href="https://github.com/firehol/netdata/wiki/Add-more-alarms-to-netdata" target="_blank"><i class="fa fa-plus" aria-hidden="true"></i> add more alarms</a></li>';
1466 sidebar += '<li class="" style="margin:20px;color:#666;"><small>netdata on <b>' + data.hostname.toString() + '</b>, collects every ' + ((data.update_every == 1)?'second':data.update_every.toString() + ' seconds') + ' <b>' + data.dimensions_count.toLocaleString() + '</b> metrics, presented as <b>' + data.charts_count.toLocaleString() + '</b> charts and monitored by <b>' + data.alarms_count.toLocaleString() + '</b> alarms, using ' + Math.round(data.rrd_memory_bytes / 1024 / 1024).toLocaleString() + ' MB of memory for ' + seconds4human(data.update_every * data.history) + ' of real-time history.<br/> <br/><b>netdata</b><br/>v' + data.version.toString() +'</small></li>';
1468 div.innerHTML = html;
1469 document.getElementById('sidebar').innerHTML = sidebar;
1473 function renderChartsAndMenu(data) {
1474 var menus = options.menus;
1475 var charts = data.charts;
1478 for(var c in charts) {
1479 if(!charts.hasOwnProperty(c)) continue;
1481 var chart = charts[c];
1482 enrichChartData(chart);
1486 if(typeof menus[m] === 'undefined') {
1488 menu_pattern: chart.menu_pattern,
1489 priority: chart.priority,
1491 title: netdataDashboard.menuTitle(chart),
1492 icon: netdataDashboard.menuIcon(chart),
1493 info: netdataDashboard.menuInfo(chart),
1494 height: netdataDashboard.menuHeight(chart) * options.chartsHeight
1498 if(typeof(menus[m].menu_pattern) === 'undefined')
1499 menus[m].menu_pattern = chart.menu_pattern;
1501 if(chart.priority < menus[m].priority)
1502 menus[m].priority = chart.priority;
1505 menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m;
1507 // create the submenu
1508 if(typeof menus[m].submenus[chart.submenu] === 'undefined') {
1509 menus[m].submenus[chart.submenu] = {
1510 priority: chart.priority,
1513 info: netdataDashboard.submenuInfo(menu_key, chart.submenu),
1514 height: netdataDashboard.submenuHeight(menu_key, chart.submenu, menus[m].height)
1518 if (chart.priority < menus[m].submenus[chart.submenu].priority)
1519 menus[m].submenus[chart.submenu].priority = chart.priority;
1522 // index the chart in the menu/submenu
1523 menus[m].submenus[chart.submenu].charts.push(chart);
1526 // propagate the descriptive subname given to QoS
1527 // to all the other submenus with the same name
1529 if(!menus.hasOwnProperty(m)) continue;
1531 for(var s in menus[m].submenus) {
1532 if(!menus[m].submenus.hasOwnProperty(s)) continue;
1534 // set the family using a name
1535 if(typeof options.submenu_names[s] !== 'undefined') {
1536 menus[m].submenus[s].title = s + ' (' + options.submenu_names[s] + ')';
1539 menu_key = (typeof(menus[m].menu_pattern) !== 'undefined')?menus[m].menu_pattern:m;
1540 menus[m].submenus[s].title = netdataDashboard.submenuTitle(menu_key, s);
1545 renderPage(menus, data);
1548 // ----------------------------------------------------------------------------
1550 function loadJs(url, callback) {
1555 xhrFields: { withCredentials: true } // required for the cookie
1558 alert('Cannot load required JS library: ' + url);
1560 .always(function() {
1561 if(typeof callback === 'function')
1566 var bootstrapTableLoaded = false;
1567 function loadBootstrapTable(callback) {
1568 if(bootstrapTableLoaded === false) {
1569 bootstrapTableLoaded = true;
1570 loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-1.11.0.min.js', function() {
1571 loadJs(NETDATA.serverDefault + 'lib/bootstrap-table-export-1.11.0.min.js', function() {
1572 loadJs(NETDATA.serverDefault + 'lib/tableExport-1.6.0.min.js', callback);
1579 function alarmsUpdateModal() {
1580 var active = '<h3>Raised Alarms</h3><table class="table">';
1581 var all = '<h3>All Running Alarms</h3><div class="panel-group" id="alarms_all_accordion" role="tablist" aria-multiselectable="true">';
1582 var footer = '<hr/><a href="https://github.com/firehol/netdata/wiki/Generating-Badges" target="_blank">netdata badges</a> refresh automatically. Their color indicates the state of the alarm: <span style="color: #e05d44"><b> red </b></span> is critical, <span style="color:#fe7d37"><b> orange </b></span> is warning, <span style="color: #4c1"><b> bright green </b></span> is ok, <span style="color: #9f9f9f"><b> light grey </b></span> is undefined (i.e. no data or no status), <span style="color: #000"><b> black </b></span> is not initialized. You can copy and paste their URLs to embed them in any web page.<br/>netdata can send notifications for these alarms. Check <a href="https://github.com/firehol/netdata/blob/master/conf.d/health_alarm_notify.conf">this configuration file</a> for more information.';
1584 NETDATA.alarms.get('all', function(data) {
1585 options.alarm_families = [];
1587 alarmsCallback(data);
1590 document.getElementById('alarms_active').innerHTML =
1591 document.getElementById('alarms_all').innerHTML =
1592 document.getElementById('alarms_log').innerHTML =
1593 'failed to load alarm data!';
1597 function alarmid4human(id) {
1601 return id.toString();
1604 function timestamp4human(timestamp, space) {
1608 if(typeof space === 'undefined')
1611 var t = new Date(timestamp * 1000);
1612 var now = new Date();
1614 if(t.toDateString() == now.toDateString())
1615 return t.toLocaleTimeString();
1617 return t.toLocaleDateString() + space + t.toLocaleTimeString();
1620 function alarm_lookup_explain(alarm, chart) {
1621 var dimensions = ' of all values ';
1623 if(chart.dimensions.length > 1)
1624 dimensions = ' of the sum of all dimensions ';
1626 if(typeof alarm.lookup_dimensions !== 'undefined') {
1627 var d = alarm.lookup_dimensions.replace('|', ',');
1628 var x = d.split(',');
1630 dimensions = 'of the sum of dimensions <code>' + alarm.lookup_dimensions + '</code> ';
1632 dimensions = 'of all values of dimension <code>' + alarm.lookup_dimensions + '</code> ';
1635 return '<code>' + alarm.lookup_method + '</code> '
1636 + dimensions + ', of chart <code>' + alarm.chart + '</code>'
1637 + ', starting <code>' + seconds4human(alarm.lookup_after + alarm.lookup_before) + '</code> and up to <code>' + seconds4human(alarm.lookup_before) + '</code>'
1638 + ((alarm.lookup_options)?(', with options <code>' + alarm.lookup_options.replace(' ', ', ') + '</code>'):'')
1642 function alarm_to_html(alarm, full) {
1643 var chart = options.data.charts[alarm.chart];
1644 if(typeof(chart) === 'undefined') {
1645 // this means the charts loaded are incomplete
1646 // probably netdata was restarted and more charts
1647 // are now available.
1651 var has_alarm = (typeof alarm.warn !== 'undefined' || typeof alarm.crit !== 'undefined');
1653 var role_href = ((has_alarm === true)?('<br/> <br/>role: <b>' + alarm.recipient + '</b><br/> <br/><b><i class="fa fa-line-chart" aria-hidden="true"></i></b><small> <a href="#" onClick="NETDATA.alarms.scrollToChart(\'' + alarm.chart + '\'); $(\'#alarmsModal\').modal(\'hide\'); return false;">jump to chart</a></small>'):(' '));
1655 var html = '<tr><td class="text-center" style="vertical-align:middle" width="40%"><b>' + alarm.chart + '</b><br/> <br/><embed src="' + NETDATA.alarms.server + '/api/v1/badge.svg?chart=' + alarm.chart + '&alarm=' + alarm.name + '&refresh=auto" type="image/svg+xml" height="20"/><br/> <br/><span style="font-size: 18px">' + alarm.info + '</span>' + role_href + '</td>'
1656 + '<td><table class="table">'
1657 + ((typeof alarm.warn !== 'undefined')?('<tr><td width="10%" style="text-align:right">warning when</td><td><span style="font-family: monospace; color:#fe7d37; font-weight: bold;">' + alarm.warn + '</span></td></tr>'):'')
1658 + ((typeof alarm.crit !== 'undefined')?('<tr><td width="10%" style="text-align:right">critical when</td><td><span style="font-family: monospace; color: #e05d44; font-weight: bold;">' + alarm.crit + '</span></td></tr>'):'');
1661 var units = chart.units;
1662 if(units === '%') units = '%';
1664 html += ((typeof alarm.lookup_after !== 'undefined')?('<tr><td width="10%" style="text-align:right">db lookup</td><td>' + alarm_lookup_explain(alarm, chart) + '</td></tr>'):'')
1665 + ((typeof alarm.calc !== 'undefined')?('<tr><td width="10%" style="text-align:right">calculation</td><td><span style="font-family: monospace;">' + alarm.calc + '</span></td></tr>'):'')
1666 + ((chart.green !== null)?('<tr><td width="10%" style="text-align:right">green threshold</td><td><code>' + chart.green + ' ' + units + '</code></td></tr>'):'')
1667 + ((chart.red !== null)?('<tr><td width="10%" style="text-align:right">red threshold</td><td><code>' + chart.red + ' ' + units + '</code></td></tr>'):'');
1671 if((alarm.delay_up_duration > 0 || alarm.delay_down_duration > 0) && alarm.delay_multiplier != 0 && alarm.delay_max_duration > 0) {
1672 if(alarm.delay_up_duration == alarm.delay_down_duration) {
1673 delay += '<small><br/>hysteresis ' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' });
1676 delay = '<small><br/>hysteresis ';
1677 if(alarm.delay_up_duration > 0) {
1678 delay += 'on escalation <code>' + seconds4human(alarm.delay_up_duration, { negative_suffix: '' }) + '</code>, ';
1680 if(alarm.delay_down_duration > 0) {
1681 delay += 'on recovery <code>' + seconds4human(alarm.delay_down_duration, { negative_suffix: '' }) + '</code>, ';
1684 if(alarm.delay_multiplier != 1.0) {
1685 delay += 'multiplied by <code>' + alarm.delay_multiplier.toString() + '</code>';
1686 delay += ', up to <code>' + seconds4human(alarm.delay_max_duration, { negative_suffix: '' }) + '</code>';
1688 delay += '</small>';
1691 html += '<tr><td width="10%" style="text-align:right">check every</td><td>' + seconds4human(alarm.update_every, { negative_suffix: '' }) + '</td></tr>'
1692 + ((has_alarm === true)?('<tr><td width="10%" style="text-align:right">execute</td><td><span style="font-family: monospace;">' + alarm.exec + '</span>' + delay + '</td></tr>'):'')
1693 + '<tr><td width="10%" style="text-align:right">source</td><td><span style="font-family: monospace;">' + alarm.source + '</span></td></tr>'
1694 + '</table></td></tr>';
1699 function alarm_family_show(id) {
1700 var html = '<table class="table">';
1701 var family = options.alarm_families[id];
1702 var len = family.arr.length;
1704 var alarm = family.arr[len];
1705 html += alarm_to_html(alarm, true);
1709 $('#alarm_all_' + id.toString()).html(html);
1712 // find the proper family of each alarm
1713 var now = Date.now();
1714 var x, family, alarm;
1715 var count_active = 0;
1718 var families_sort = [];
1719 for(x in data.alarms) {
1720 if(!data.alarms.hasOwnProperty(x)) continue;
1722 alarm = data.alarms[x];
1723 family = alarm.family;
1726 var chart = options.data.charts[alarm.chart];
1727 if(typeof chart === 'undefined')
1728 chart = options.data.charts_by_name[alarm.chart];
1730 // not found - this should never happen!
1731 if(typeof chart === 'undefined') {
1732 console.log('WARNING: alarm ' + x + ' is linked to chart ' + alarm.chart + ', which is not found in the list of chart got from the server.');
1733 chart = { priority: 9999999 };
1735 else if(typeof chart.menu !== 'undefined' && typeof chart.submenu !== 'undefined')
1736 // the family based on the chart
1737 family = chart.menu + ' - ' + chart.submenu;
1739 if(typeof families[family] === 'undefined') {
1740 families[family] = {
1743 priority: chart.priority
1746 families_sort.push(families[family]);
1749 if(chart.priority < families[family].priority)
1750 families[family].priority = chart.priority;
1752 families[family].arr.unshift(alarm);
1755 // sort the families, like the dashboard menu does
1756 var families_sorted = families_sort.sort(function (a, b) {
1757 if (a.priority > b.priority) return -1;
1758 if (a.priority < b.priority) return 1;
1763 var len = families_sorted.length;
1765 family = families_sorted[len].name;
1766 var active_family_added = false;
1767 var expanded = 'true';
1772 all += "</table></div></div></div>";
1774 collapsed = 'class="collapsed"';
1778 all += '<div class="panel panel-default"><div class="panel-heading" role="tab" id="alarm_all_heading_' + fc.toString() + '"><h4 class="panel-title"><a ' + collapsed + ' role="button" data-toggle="collapse" data-parent="#alarms_all_accordion" href="#alarm_all_' + fc.toString() + '" aria-expanded="' + expanded + '" aria-controls="alarm_all_' + fc.toString() + '">' + family.toString() + '</a></h4></div><div id="alarm_all_' + fc.toString() + '" class="panel-collapse collapse ' + cin + '" role="tabpanel" aria-labelledby="alarm_all_heading_' + fc.toString() + '" data-alarm-id="' + fc.toString() + '"><div class="panel-body" id="alarm_all_body_' + fc.toString() + '">';
1780 options.alarm_families[fc] = families[family];
1784 var arr = families[family].arr;
1788 if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL') {
1789 if(!active_family_added) {
1790 active_family_added = true;
1791 active += '<tr><th class="text-center" colspan="2"><h4>' + family + '</h4></th></tr>';
1794 active += alarm_to_html(alarm, true);
1800 active += "</table>";
1801 if(families_sorted.length > 0) all += "</div></div></div>";
1805 active += "<h4>Everything is normal. No raised alarms.</h4>";
1810 all += "<h4>No alarms are running in this system.</h4>";
1814 document.getElementById('alarms_active').innerHTML = active;
1815 document.getElementById('alarms_all').innerHTML = all;
1817 if(families_sorted.length > 0) alarm_family_show(0);
1819 // register bootstrap events
1820 var $accordion = $('#alarms_all_accordion');
1821 $accordion.on('show.bs.collapse', function (d) {
1822 var target = $(d.target);
1823 var id = $(target).data('alarm-id');
1824 alarm_family_show(id);
1826 $accordion.on('hidden.bs.collapse', function (d) {
1827 var target = $(d.target);
1828 var id = $(target).data('alarm-id');
1829 $('#alarm_all_' + id.toString()).html('');
1832 document.getElementById('alarms_log').innerHTML = '<h3>Alarm Log</h3><table id="alarms_log_table"></table>';
1834 loadBootstrapTable(function () {
1835 $('#alarms_log_table').bootstrapTable({
1836 url: NETDATA.alarms.server + '/api/v1/alarm_log?all',
1840 showPaginationSwitch: false,
1843 searchAlign: 'left',
1846 exportDataType: 'basic',
1848 fileName: 'netdata_alarm_log'
1850 rowStyle: function(row, index) {
1853 switch(row.status) {
1854 case 'CRITICAL' : return { classes: 'danger' }; break;
1855 case 'WARNING' : return { classes: 'warning' }; break;
1856 case 'UNDEFINED': return { classes: 'info' }; break;
1857 case 'CLEAR' : return { classes: 'success' }; break;
1870 title: 'Event Date',
1872 titleTooltip: 'The date and time the even took place',
1873 formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
1882 titleTooltip: 'The host that generated this event',
1890 titleTooltip: 'The host unique ID for this event',
1891 formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
1900 titleTooltip: 'The ID of the alarm that generated this event',
1901 formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
1908 field: 'alarm_event_id',
1909 title: 'Alarm Event ID',
1910 titleTooltip: 'The incremental ID of this event for the given alarm',
1911 formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
1920 titleTooltip: 'The chart the alarm is attached to',
1929 titleTooltip: 'The family of the chart the alarm is attached to',
1938 titleTooltip: 'The alarm name that generated this event',
1939 formatter: function(value, row, index) {
1942 return value.toString().replace(/_/g, ' ');
1950 field: 'value_string',
1951 title: 'Friendly Value',
1952 titleTooltip: 'The value of the alarm, that triggered this event',
1958 field: 'old_value_string',
1959 title: 'Friendly Old Value',
1960 titleTooltip: 'The value of the alarm, just before this event',
1969 titleTooltip: 'The value of the alarm, just before this event',
1970 formatter: function(value, row, index) {
1973 return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1983 titleTooltip: 'The value of the alarm, that triggered this event',
1984 formatter: function(value, row, index) {
1987 return ((value !== null)?Math.round(value * 100) / 100:'NaN').toString();
1997 titleTooltip: 'The units of the value of the alarm',
2004 field: 'old_status',
2005 title: 'Old Status',
2006 titleTooltip: 'The status of the alarm, just before this event',
2015 titleTooltip: 'The status of the alarm, that was set due to this event',
2023 title: 'Last Duration',
2024 titleTooltip: 'The duration the alarm was at its previous state, just before this event',
2025 formatter: function(value, row, index) {
2028 return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2036 field: 'non_clear_duration',
2037 title: 'Raised Duration',
2038 titleTooltip: 'The duration the alarm was raised, just before this event',
2039 formatter: function(value, row, index) {
2042 return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2052 titleTooltip: 'The recipient of this event',
2060 title: 'Processed Status',
2061 titleTooltip: 'True when this event is processed',
2062 formatter: function(value, row, index) {
2078 title: 'Updated Status',
2079 titleTooltip: 'True when this event has been updated by another event',
2080 formatter: function(value, row, index) {
2095 field: 'updated_by_id',
2096 title: 'Updated By ID',
2097 titleTooltip: 'The unique ID of the event that obsoleted this one',
2098 formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
2105 field: 'updates_id',
2106 title: 'Updates ID',
2107 titleTooltip: 'The unique ID of the event obsoleted because of this event',
2108 formatter: function(value, row, index) { void(row); void(index); return alarmid4human(value); },
2117 titleTooltip: 'The script to handle the event notification',
2125 title: 'Script Run At',
2126 titleTooltip: 'The date and time the script has been ran',
2127 formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
2135 title: 'Script Return Value',
2136 titleTooltip: 'The return code of the script',
2137 formatter: function(value, row, index) {
2142 return 'OK (returned 0)';
2144 return 'FAILED (with code ' + value.toString() + ')';
2153 title: 'Script Delay',
2154 titleTooltip: 'The hysteresis of the notification',
2155 formatter: function(value, row, index) {
2159 return seconds4human(value, { negative_suffix: '', space: ' ', now: 'no time' });
2167 field: 'delay_up_to_timestamp',
2168 title: 'Script Delay Run At',
2169 titleTooltip: 'The date and time the script should be run, after hysteresis',
2170 formatter: function(value, row, index) { void(row); void(index); return timestamp4human(value, ' '); },
2178 title: 'Description',
2179 titleTooltip: 'A short description of the alarm',
2187 title: 'Alarm Source',
2188 titleTooltip: 'The source of configuration of the alarm',
2196 // console.log($('#alarms_log_table').bootstrapTable('getOptions'));
2201 function seconds4human(seconds, options) {
2202 var default_options = {
2205 negative_suffix: 'ago',
2215 if(typeof options !== 'object')
2216 options = default_options;
2219 for(x in default_options) {
2220 if(typeof options[x] !== 'string')
2221 options[x] = default_options[x];
2225 if(typeof seconds === 'string')
2226 seconds = parseInt(seconds);
2234 if(options.negative_suffix !== '') suffix = options.space + options.negative_suffix;
2237 var hours = Math.floor(seconds / 3600);
2238 seconds -= (hours * 3600);
2240 var minutes = Math.floor(seconds / 60);
2241 seconds -= (minutes * 60);
2245 if(hours > 1) txt += hours.toString() + options.space + options.hours;
2246 else if(hours === 1) txt += hours.toString() + options.space + options.hour;
2248 if(hours > 0 && minutes > 0 && seconds == 0)
2249 txt += options.space + options.and + options.space;
2250 else if(hours > 0 && minutes > 0 && seconds > 0)
2251 txt += ',' + options.space;
2253 if(minutes > 1) txt += minutes.toString() + options.space + options.minutes;
2254 else if(minutes === 1) txt += minutes.toString() + options.space + options.minute;
2256 if((minutes > 0 || minutes > 0) && seconds > 0)
2257 txt += options.space + options.and + options.space;
2259 if(seconds > 1) txt += Math.floor(seconds).toString() + options.space + options.seconds;
2260 else if(seconds === 1) txt += Math.floor(seconds).toString() + options.space + options.second;
2262 return txt + suffix;
2265 function alarmsCallback(data) {
2267 for(x in data.alarms) {
2268 if(!data.alarms.hasOwnProperty(x)) continue;
2270 var alarm = data.alarms[x];
2271 if(alarm.status === 'WARNING' || alarm.status === 'CRITICAL')
2276 document.getElementById('alarms_count_badge').innerHTML = count.toString();
2278 document.getElementById('alarms_count_badge').innerHTML = '';
2281 function initializeDynamicDashboard(netdata_url) {
2282 if(typeof netdata_url === 'undefined' || netdata_url === null)
2283 netdata_url = NETDATA.serverDefault;
2285 // initialize clickable alarms
2286 NETDATA.alarms.chart_div_offset = 100;
2287 NETDATA.alarms.chart_div_id_prefix = 'chart_';
2288 NETDATA.alarms.chart_div_animation_duration = 0;
2290 NETDATA.pause(function() {
2291 NETDATA.alarms.callback = alarmsCallback;
2293 // download all the charts the server knows
2294 NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
2296 options.hostname = data.hostname;
2297 options.data = data;
2298 options.version = data.version;
2299 netdataDashboard.os = data.os;
2301 if(typeof data.hosts != 'undefined')
2302 options.hosts = data.hosts;
2304 // update the dashboard hostname
2305 document.getElementById('hostname').innerHTML = options.hostname;
2306 document.getElementById('hostname').href = NETDATA.serverDefault;
2307 document.getElementById('netdataVersion').innerHTML = options.version;
2309 // update the dashboard title
2310 document.title = options.hostname + ' netdata dashboard';
2312 // close the splash screen
2313 $("#loadOverlay").css("display","none");
2315 // create a chart_by_name index
2316 data.charts_by_name = {};
2317 var charts = data.charts;
2320 if(!charts.hasOwnProperty(x)) continue;
2322 var chart = charts[x];
2323 data.charts_by_name[chart.name] = chart;
2326 // render all charts
2327 renderChartsAndMenu(data);
2333 // ----------------------------------------------------------------------------
2335 function versionLog(msg) {
2336 document.getElementById('versionCheckLog').innerHTML = msg;
2339 function getNetdataCommitIdFromVersion() {
2340 var s = options.version.split('-');
2342 if(s.length !== 3) return null;
2343 if(s[2][0] == 'g') {
2344 var v = s[2].split('_')[0].substring(1, 8);
2345 if(v.length === 7) {
2346 versionLog('Installed git commit id of netdata is ' + v);
2347 document.getElementById('netdataCommitId').innerHTML = v;
2354 function getNetdataCommitId(force, callback) {
2355 versionLog('Downloading installed git commit id from netdata...');
2361 xhrFields: { withCredentials: true } // required for the cookie
2363 .done(function(data) {
2364 data = data.replace(/(\r\n|\n|\r| |\t)/gm,"");
2366 var c = getNetdataCommitIdFromVersion();
2367 if(c !== null && data.length === 40 && data.substring(0, 7) !== c) {
2368 versionLog('Installed files commit id and internal netdata git commit id do not match');
2372 if(data.length >= 7) {
2373 versionLog('Installed git commit id of netdata is ' + data);
2374 document.getElementById('netdataCommitId').innerHTML = data.substring(0, 7);
2379 versionLog('Failed to download installed git commit id from netdata!');
2381 if(force === true) {
2382 var c = getNetdataCommitIdFromVersion();
2383 if(c === null) versionLog('Cannot find the git commit id of netdata.');
2391 function getGithubLatestCommit(callback) {
2392 versionLog('Downloading latest git commit id info from github...');
2395 url: 'https://api.github.com/repos/firehol/netdata/commits',
2399 .done(function(data) {
2400 versionLog('Latest git commit id from github is ' + data[0].sha);
2401 callback(data[0].sha);
2404 versionLog('Failed to download installed git commit id from github!');
2409 function checkForUpdate(force, callback) {
2410 getNetdataCommitId(force, function(sha1) {
2411 if(sha1 === null) callback(null, null);
2413 getGithubLatestCommit(function(sha2) {
2414 callback(sha1, sha2);
2421 function notifyForUpdate(force) {
2422 versionLog('<p>checking for updates...</p>');
2424 var now = Date.now();
2426 if(typeof force === 'undefined' || force !== true) {
2427 var last = loadLocalStorage('last_update_check');
2429 if(typeof last === 'string')
2430 last = parseInt(last);
2434 if(now - last < 3600000 * 8) {
2435 // no need to check it - too soon
2440 checkForUpdate(force, function(sha1, sha2) {
2445 versionLog('<p><big>Failed to get your netdata git commit id!</big></p><p>You can always get the latest netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
2447 else if(sha2 === null) {
2449 versionLog('<p><big>Failed to get the latest git commit id from github.</big></p><p>You can always get the latest netdata from <a href="https://github.com/firehol/netdata" target="_blank">its github page</a>.</p>');
2451 else if(sha1 === sha2) {
2453 versionLog('<p><big>You already have the latest netdata!</big></p><p>No update yet?<br/>Probably, we need some motivation to keep going on!</p><p>If you haven\'t already, <a href="https://github.com/firehol/netdata" target="_blank">give netdata a <b>Star</b> at its github page</a>.</p>');
2457 var compare = 'https://github.com/firehol/netdata/compare/' + sha1.toString() + '...' + sha2.toString();
2459 versionLog('<p><big><strong>New version of netdata available!</strong></big></p><p>Latest commit: <b><code>' + sha2.substring(0, 7).toString() + '</code></b></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>');
2461 document.getElementById('update_badge').innerHTML = '!';
2465 saveLocalStorage('last_update_check', now.toString());
2469 // ----------------------------------------------------------------------------
2471 function finalizePage() {
2472 // resize all charts - without starting the background thread
2473 // this has to be done while NETDATA is paused
2474 // if we ommit this, the affix menu will be wrong, since all
2475 // the Dom elements are initially zero-sized
2478 if(urlOptions.pan_and_zoom === true)
2479 NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
2481 // ------------------------------------------------------------------------
2482 // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
2483 $.fn.shorten = function(settings) {
2489 ellipsesText: "...",
2490 moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
2491 lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
2492 onLess: function() { NETDATA.onscroll(); },
2493 onMore: function() { NETDATA.onscroll(); },
2499 $.extend(config, settings);
2502 if ($(this).data('jquery.shorten') && !config.force) {
2505 $(this).data('jquery.shorten', true);
2507 $(document).off("click", '.morelink');
2512 var $this = $(this);
2513 if ($this.hasClass('less')) {
2514 $this.removeClass('less');
2515 $this.html(config.moreText);
2516 $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
2521 $this.addClass('less');
2522 $this.html(config.lessText);
2523 $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
2531 return this.each(function() {
2532 var $this = $(this);
2534 var content = $this.html();
2535 var contentlen = $this.text().length;
2536 if (contentlen > config.showChars + config.minHideChars) {
2537 var c = content.substr(0, config.showChars);
2538 if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
2540 var inTag = false; // I'm in a tag?
2541 var bag = ''; // Put the characters to be shown here
2542 var countChars = 0; // Current bag size
2543 var openTags = []; // Stack for opened tags, so I can close them later
2546 for (var i = 0, r = 0; r <= config.showChars; i++) {
2547 if (content[i] == '<' && !inTag) {
2550 // This could be "tag" or "/tag"
2551 tagName = content.substring(i + 1, content.indexOf('>', i));
2553 // If its a closing tag
2554 if (tagName[0] == '/') {
2557 if (tagName != '/' + openTags[0]) {
2558 config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
2560 openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
2564 // There are some nasty tags that don't have a close tag like <br/>
2565 if (tagName.toLowerCase() != 'br') {
2566 openTags.unshift(tagName); // Add to start the name of the tag that opens
2570 if (inTag && content[i] == '>') {
2574 if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
2577 if (countChars <= config.showChars) {
2578 bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
2580 } else // Now I have the characters needed
2582 if (openTags.length > 0) // I have unclosed tags
2584 //console.log('They were open tags');
2585 //console.log(openTags);
2586 for (var j = 0; j < openTags.length; j++) {
2587 //console.log('Cierro tag ' + openTags[j]);
2588 bag += '</' + openTags[j] + '>'; // Close all tags that were opened
2590 // You could shift the tag from the stack to check if you end with an empty stack, that means you have closed all open tags
2597 c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
2599 c+=config.ellipsesText;
2602 var html = '<div class="shortcontent">' + c +
2603 '</div><div class="allcontent">' + content +
2604 '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
2607 $this.find(".allcontent").hide(); // Hide all text
2608 $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
2613 $(".chart-message").shorten();
2614 // ------------------------------------------------------------------------
2616 // callback for us to track PanAndZoom operations
2617 NETDATA.globalPanAndZoom.callback = urlOptions.netdataPanAndZoomCallback;
2619 // let it run (update the charts)
2622 // check if we have to jump to a specific section
2623 scrollToId(urlOptions.hash.replace('#',''));
2625 if(urlOptions.chart !== null) {
2626 NETDATA.alarms.scrollToChart(urlOptions.chart);
2627 //urlOptions.hash = '#' + NETDATA.name2id('menu_' + charts[c].menu + '_submenu_' + charts[c].submenu);
2628 //urlOptions.hash = '#chart_' + NETDATA.name2id(urlOptions.chart);
2629 //console.log('hash = ' + urlOptions.hash);
2632 var $sidebar = $('#sidebar');
2633 /* activate bootstrap sidebar (affix) */
2636 top: (isdemo())?150:0,
2641 /* fix scrolling of very long affix lists
2642 http://stackoverflow.com/questions/21691585/bootstrap-3-1-0-affix-too-long
2644 $sidebar.on('affixed.bs.affix', function() {
2645 $(this).removeAttr('style');
2648 /* activate bootstrap scrollspy (needed for sidebar) */
2649 $(document.body).scrollspy({
2651 offset: $(window).height() / 5 // controls the diff of the <hX> element to the top, to select it
2654 // change the URL based on the current position of the screen
2655 $sidebar.on('activate.bs.scrollspy', function (e) {
2657 var el = $(e.target);
2658 //if(el.find('ul').size() == 0) {
2659 var hash = el.find('a').attr('href');
2660 if(typeof hash === 'string' && hash.substring(0, 1) === '#' && urlOptions.hash.startsWith(hash + '_submenu_') === false) {
2661 urlOptions.hash = hash;
2662 //console.log(urlOptions.hash);
2663 urlOptions.hashUpdate();
2665 //else console.log('hash: not accepting ' + hash);
2667 //else console.log('el.find(): not found');
2670 document.getElementById('footer').style.display = 'block';
2672 var update_options_modal = function() {
2673 // console.log('update_options_modal');
2675 var sync_option = function(option) {
2676 var self = $('#' + option);
2678 if(self.prop('checked') !== NETDATA.getOption(option)) {
2679 // console.log('switching ' + option.toString());
2680 self.bootstrapToggle(NETDATA.getOption(option)?'on':'off');
2684 var theme_sync_option = function(option) {
2685 var self = $('#' + option);
2687 self.bootstrapToggle(netdataTheme === 'slate'?'on':'off');
2690 sync_option('eliminate_zero_dimensions');
2691 sync_option('destroy_on_hide');
2692 sync_option('async_on_scroll');
2693 sync_option('parallel_refresher');
2694 sync_option('concurrent_refreshes');
2695 sync_option('sync_selection');
2696 sync_option('sync_pan_and_zoom');
2697 sync_option('stop_updates_when_focus_is_lost');
2698 sync_option('smooth_plot');
2699 sync_option('pan_and_zoom_data_padding');
2700 sync_option('show_help');
2701 theme_sync_option('netdata_theme_control');
2703 if(NETDATA.getOption('parallel_refresher') === false) {
2704 $('#concurrent_refreshes_row').hide();
2707 $('#concurrent_refreshes_row').show();
2710 NETDATA.setOption('setOptionCallback', update_options_modal);
2712 // handle options changes
2713 $('#eliminate_zero_dimensions').change(function() { NETDATA.setOption('eliminate_zero_dimensions', $(this).prop('checked')); });
2714 $('#destroy_on_hide').change(function() { NETDATA.setOption('destroy_on_hide', $(this).prop('checked')); });
2715 $('#async_on_scroll').change(function() { NETDATA.setOption('async_on_scroll', $(this).prop('checked')); });
2716 $('#parallel_refresher').change(function() { NETDATA.setOption('parallel_refresher', $(this).prop('checked')); });
2717 $('#concurrent_refreshes').change(function() { NETDATA.setOption('concurrent_refreshes', $(this).prop('checked')); });
2718 $('#sync_selection').change(function() { NETDATA.setOption('sync_selection', $(this).prop('checked')); });
2719 $('#sync_pan_and_zoom').change(function() { NETDATA.setOption('sync_pan_and_zoom', $(this).prop('checked')); });
2720 $('#stop_updates_when_focus_is_lost').change(function() {
2721 urlOptions.update_always = !$(this).prop('checked');
2722 urlOptions.hashUpdate();
2724 NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2726 $('#smooth_plot').change(function() { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
2727 $('#pan_and_zoom_data_padding').change(function() { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
2728 $('#show_help').change(function() {
2729 urlOptions.help = $(this).prop('checked');
2730 urlOptions.hashUpdate();
2732 NETDATA.setOption('show_help', urlOptions.help);
2736 // this has to be the last
2737 // it reloads the page
2738 $('#netdata_theme_control').change(function() {
2739 urlOptions.theme = $(this).prop('checked')?'slate':'white';
2740 urlOptions.hashUpdate();
2742 if(setTheme(urlOptions.theme))
2746 var $updateModal = $('#updateModal');
2747 $updateModal.on('show.bs.modal', function() {
2748 versionLog('checking, please wait...');
2751 $updateModal.on('shown.bs.modal', function() {
2752 notifyForUpdate(true);
2755 var $alarmsModal = $('#alarmsModal');
2756 $alarmsModal.on('shown.bs.modal', function() {
2757 NETDATA.pause(alarmsUpdateModal);
2760 $alarmsModal.on('hidden.bs.modal', function() {
2762 document.getElementById('alarms_active').innerHTML =
2763 document.getElementById('alarms_all').innerHTML =
2764 document.getElementById('alarms_log').innerHTML =
2768 $('#deleteRegistryModal').on('hidden.bs.modal', function() {
2769 deleteRegistryGuid = null;
2773 // do not to give errors on netdata demo servers for 60 seconds
2774 NETDATA.options.current.retries_on_data_failures = 60;
2776 if(urlOptions.nowelcome !== true) {
2777 setTimeout(function() {
2778 $('#welcomeModal').modal();
2782 // google analytics when this is used for the home page of the demo sites
2783 // this does not run on user's installations
2784 setTimeout(function() {
2785 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
2786 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
2787 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
2788 })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
2790 ga('create', 'UA-64295674-3', 'auto');
2791 ga('send', 'pageview');
2794 else notifyForUpdate();
2796 if(urlOptions.show_alarms === true)
2797 setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000);
2799 var sidebar = document.getElementById('sidebar');
2800 Ps.initialize(sidebar, {
2802 wheelPropagation: true,
2803 swipePropagation: true,
2804 minScrollbarLength: null,
2805 maxScrollbarLength: null,
2806 useBothWheelAxes: false,
2807 suppressScrollX: true,
2808 suppressScrollY: false,
2809 scrollXMarginOffset: 0,
2810 scrollYMarginOffset: 0,
2815 var registry = document.getElementById('myNetdataDropdownUL');
2816 Ps.initialize(registry, {
2818 wheelPropagation: false,
2819 swipePropagation: false,
2820 minScrollbarLength: null,
2821 maxScrollbarLength: null,
2822 useBothWheelAxes: false,
2823 suppressScrollX: true,
2824 suppressScrollY: false,
2825 scrollXMarginOffset: 0,
2826 scrollYMarginOffset: 0,
2829 Ps.update(registry);
2831 NETDATA.onresizeCallback = function() {
2833 Ps.update(registry);
2836 $('#myNetdataDropdownParent')
2837 .on('show.bs.dropdown', function () {
2838 NETDATA.pause(function() {});
2840 .on('shown.bs.dropdown', function () {
2841 Ps.update(registry);
2843 .on('hidden.bs.dropdown', function () {
2847 // var netdataEnded = performance.now();
2848 // console.log('start up time: ' + (netdataEnded - netdataStarted).toString() + ' ms');
2851 function resetDashboardOptions() {
2852 var help = NETDATA.options.current.show_help;
2854 NETDATA.resetOptions();
2855 if(setTheme('slate'))
2858 if(help !== NETDATA.options.current.show_help)
2862 // callback to add the dashboard info to the
2863 // parallel javascript downloader in netdata
2864 var netdataPrepCallback = function() {
2865 NETDATA.requiredCSS.push({
2866 url: NETDATA.serverDefault + 'css/bootstrap-toggle-2.2.2.min.css',
2867 isAlreadyLoaded: function() { return false; }
2870 NETDATA.requiredJs.push({
2871 url: NETDATA.serverDefault + 'lib/bootstrap-toggle-2.2.2.min.js',
2872 isAlreadyLoaded: function() { return false; }
2875 NETDATA.requiredJs.push({
2876 url: NETDATA.serverDefault + 'dashboard_info.js?v20170213-2',
2878 isAlreadyLoaded: function() { return false; }
2882 document.getElementById('masthead').style.display = 'block';
2885 if(urlOptions.update_always === true)
2886 NETDATA.setOption('stop_updates_when_focus_is_lost', !urlOptions.update_always);
2891 // var netdataStarted = performance.now();
2892 var netdataCallback = initializeDynamicDashboard;
2896 <body data-spy="scroll" data-target="#sidebar">
2897 <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
2898 netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
2900 <script type="text/javascript">
2901 // change the loadOverlay colors ASAP to match the theme
2902 document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
2904 <nav class="navbar navbar-default navbar-fixed-top" role="banner">
2905 <div class="container">
2906 <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
2907 <ul class="nav navbar-nav">
2908 <li class="dropdown" id="myNetdataDropdownParent">
2909 <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a>
2910 <ul class="dropdown-menu scrollable-menu inpagemenu multi-column columns-2" role="menu" id="myNetdataDropdownUL">
2912 <div class="col-sm-6" style="width: 85%; padding-right: 0;">
2913 <ul id="mynetdata_servers" class="multi-column-dropdown">
2914 <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2917 <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
2918 <ul id="mynetdata_actions1" class="multi-column-dropdown">
2919 <li style="color: #999;"> </li>
2927 <div class="navbar-header">
2928 <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse">
2929 <span class="sr-only">Toggle navigation</span>
2930 <span class="icon-bar"></span>
2931 <span class="icon-bar"></span>
2932 <span class="icon-bar"></span>
2934 <a href="/" class="navbar-brand" id="hostname" title="reload the dashboard">netdata</a>
2936 <nav class="collapse navbar-collapse navbar-right" role="navigation">
2937 <ul class="nav navbar-nav">
2938 <li><a href="#" class="btn" data-toggle="modal" data-target="#alarmsModal" title="alarms"><i class="fa fa-bell"></i> <span class="hidden-sm">Alarms </span><span id="alarms_count_badge" class="badge"></span></a></li>
2939 <li><a href="#" class="btn" data-toggle="modal" data-target="#optionsModal" title="dashboard settings"><i class="fa fa-sliders"></i> <span class="hidden-sm">Settings</span></a></li>
2940 <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 class="hidden-sm hidden-md">Update </span><span id="update_badge" class="badge"></span></a></li>
2941 <li><a href="https://github.com/firehol/netdata/wiki" class="btn" target="_blank" title="netdata on github"><i class="fa fa-github"></i></a></li>
2942 <li><a href="https://twitter.com/linuxnetdata" class="btn" target="_blank" title="netdata on twitter"><i class="fa fa-twitter" aria-hidden="true"></i></a></li>
2943 <li><a href="https://www.facebook.com/linuxnetdata/" class="btn" target="_blank" title="netdata on facebook"><i class="fa fa-facebook-official" aria-hidden="true"></i></a></li>
2944 <li class="hidden-sm"><a href="#" class="btn" data-toggle="modal" data-target="#helpModal" title="dashboard help"><i class="fa fa-question-circle"></i> <span class="hidden-sm hidden-md">Help</span></a></li>
2945 <li class="dropdown hidden-sm hidden-md hidden-lg">
2946 <a href="#" class="dropdown-toggle" data-toggle="dropdown">my-netdata <strong class="caret"></strong></a>
2947 <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
2948 <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
2956 <div id="masthead" style="display: none;">
2957 <div class="container">
2959 <div class="col-md-7">
2961 <p class="lead">Real-time performance monitoring, in the greatest possible detail</p>
2964 <div class="col-md-5">
2965 <div class="well well-lg">
2967 <div class="col-md-6">
2968 <b>Drag</b> charts to pan.
2969 <b>Shift + wheel</b> on them, to zoom in and out.
2970 <b>Double-click</b> on them, to reset.
2971 <b>Hover</b> on them too!
2973 <div class="col-md-6">
2974 <div data-netdata="system.intr" data-chart-library="dygraph" data-dygraph-theme="sparkline" data-dygraph-type="line" data-dygraph-strokewidth="3" data-dygraph-smooth="true" data-dygraph-highlightcirclesize="6" data-after="-90" data-height="60px" data-colors="#C66"></div>
2983 <div class="container">
2985 <div class="charts-body" role="main">
2986 <div id="charts_div"></div>
2988 <div class="sidebar-body hidden-xs hidden-sm" id="sidebar-body" role="complementary">
2989 <nav class="dashboard-sidebar hidden-print hidden-xs hidden-sm" id="sidebar" role="menu"></nav>
2994 <div id="footer" class="container" style="display: none;">
2996 <div class="col-md-10" role="main">
2998 <big><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></big><br/>
2999 <i class="fa fa-copyright"></i> Copyright 2016-2017, <a href="mailto:costa@tsaousis.gr">Costa Tsaousis</a>.<br/>
3000 Released under <a href="http://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPL v3 or later</a>.<br/>
3004 <a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a> re-distributes these software tools:
3006 <i class="fa fa-circle"></i> The excellent <a href="http://dygraphs.com/" target="_blank">Dygraphs.com</a> web chart library,
3007 <i class="fa fa-copyright"></i> Copyright 2009, Dan Vanderkam, <a href="http://dygraphs.com/legal.html" target="_blank">MIT License</a>
3009 <i class="fa fa-circle"></i> <a href="https://rendro.github.io/easy-pie-chart/" target="_blank">Easy Pie Chart</a> web chart library,
3010 <i class="fa fa-copyright"></i> Copyright 2013, Robert Fleischmann, <a href="https://github.com/rendro/easy-pie-chart/blob/master/LICENSE" target="_blank">MIT License</a>
3012 <i class="fa fa-circle"></i> <a href="http://bernii.github.io/gauge.js/" target="_blank">Gauge.js</a> web chart library,
3013 <i class="fa fa-copyright"></i> Copyright, Bernard Kobos, <a href="http://bernii.github.io/gauge.js/" target="_blank">MIT License</a>
3015 <i class="fa fa-circle"></i> <a href="https://jquery.org/" target="_blank">jQuery</a>,
3016 <i class="fa fa-copyright"></i> Copyright 2015, jQuery Foundation, <a href="https://jquery.org/license/" target="_blank">MIT License</a>
3018 <i class="fa fa-circle"></i> <a href="http://getbootstrap.com/getting-started/" target="_blank">Bootstrap</a>,
3019 <i class="fa fa-copyright"></i> Copyright 2015, Twitter, <a href="http://getbootstrap.com/getting-started/#license-faqs" target="_blank">MIT License</a>
3021 <i class="fa fa-circle"></i> <a href="http://www.bootstraptoggle.com/" target="_blank">Bootstrap Toggle</a>,
3022 <i class="fa fa-copyright"></i> Copyright (c) 2011-2014 Min Hur, The New York Times Company, <a href="https://github.com/minhur/bootstrap-toggle/blob/master/LICENSE" target="_blank">MIT License</a>
3024 <i class="fa fa-circle"></i> <a href="https://github.com/noraesae/perfect-scrollbar" target="_blank">perfect-scrollbar</a>,
3025 <i class="fa fa-copyright"></i> Copyright 2016, Hyunje Alex Jun and other contributors, <a href="https://github.com/noraesae/perfect-scrollbar/blob/master/LICENSE" target="_blank">MIT License</a>
3027 <i class="fa fa-circle"></i> <a href="https://fortawesome.github.io/Font-Awesome/" target="_blank">FontAwesome</a>,
3028 <i class="fa fa-copyright"></i> Created by Dave Gandy, Font: <a href="http://scripts.sil.org/OFL" target="_blank">SIL OFL 1.1 License</a>, CSS: <a href="http://opensource.org/licenses/mit-license.html" target="_blank">MIT License</a>
3030 <i class="fa fa-circle"></i> <a href="http://www.iconsdb.com/soylent-red-icons/seo-performance-icon.html" target="_blank">IconsDB.com Icons</a>, Icons provided as CC0 1.0 Universal (CC0 1.0) Public Domain Dedication.
3032 <i class="fa fa-circle"></i> <a href="http://bootstrap-table.wenzhixin.net.cn/" target="_blank">bootstrap-table</a>,
3033 <i class="fa fa-copyright"></i> Copyright (c) 2012-2016 Zhixin Wen, <a href="https://github.com/wenzhixin/bootstrap-table/blob/master/LICENSE" target="_blank">MIT License</a>
3035 <i class="fa fa-circle"></i> <a href="https://github.com/hhurz/tableExport.jquery.plugin" target="_blank">tableExport.jquery.plugin</a>,
3036 <i class="fa fa-copyright"></i> Copyright (c) 2015,2016 hhurz, <a href="http://rawgit.com/hhurz/tableExport.jquery.plugin/master/tableExport.js" target="_blank">MIT License</a>
3044 <div class="modal fade" id="welcomeModal" tabindex="-1" role="dialog" aria-labelledby="welcomeModalLabel">
3045 <div class="modal-dialog modal-lg" role="document">
3046 <div class="modal-content">
3047 <div class="modal-header">
3048 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3049 <h4 class="modal-title" id="welcomeModalLabel">Welcome to the world of netdata</h4>
3051 <div class="modal-body">
3053 <div style="width: 100%; text-align: center; padding-top: 10px; padding-bottom: 10px; font-size: 18px;">
3054 if there is a metric for something, we want it visualised<br/>
3055 and we want this visualisation to be <strong>real-time</strong>, <strong>efficient</strong> and <strong>awesome</strong>
3059 <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>
3060 is a new way to monitor your systems and applications, to get <strong>real-time insights</strong>
3061 of what is really happening and what affects performance.
3062 It is carefully optimised to be a real-time system, without interfering in any way,
3063 to the core function of your systems.
3066 <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b>
3067 has been designed to monitor <strong>massive amounts of metrics, per server, per second</strong>.
3068 When installed, it might come up with 1k to 3k metrics, but we have been testing it with 100k
3069 metrics, all collected per second, and still the cpu utilisation remained negligible.
3071 We have also tried to give each metric, a meaning, a context.
3072 We have grouped and categorized all metrics into meaningful charts, providing a
3073 better understanding of the underlying technologies and mechanisms.
3076 <b><a href="https://github.com/firehol/netdata/wiki" target="_blank">netdata</a></b> is free,
3077 open-source software. If you decide to use it,
3078 <strong><a href="https://github.com/firehol/netdata/wiki/a-github-star-is-important" target="_blank">it is important to give netdata a star at GitHub</a></strong>.
3081 Enjoy real-time performance monitoring!
3087 <div class="modal-footer">
3088 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3094 <div class="modal fade" id="helpModal" tabindex="-1" role="dialog" aria-labelledby="helpModalLabel">
3095 <div class="modal-dialog modal-lg" role="document">
3096 <div class="modal-content">
3097 <div class="modal-header">
3098 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3099 <h4 class="modal-title" id="helpModalLabel">Dashboard Help</h4>
3101 <div class="modal-body">
3103 <h4>Dygraphs (line, area and stacked area charts)</h4>
3106 <ul class="nav nav-tabs" role="tablist">
3107 <li role="presentation" class="active"><a href="#help_mouse" aria-controls="help_mouse" role="tab" data-toggle="tab">Mouse Interface</a></li>
3108 <li role="presentation"><a href="#help_touch" aria-controls="help_touch" role="tab" data-toggle="tab">Touch Interface</a></li>
3112 <div class="tab-content">
3113 <div role="tabpanel" class="tab-pane active" id="help_mouse">
3115 <h4>Mouse Over / Hover</h4>
3116 Mouse over on a chart to show, at its legend, the values for the timestamp under the mouse (the chart will also highlight the point at the chart).
3118 All the other visible charts will also show and highlight their values for the same timestamp.
3122 <h4>Drag Chart Contents</h4>
3123 Drag the contents of a chart to pan it horizontally.
3125 All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring).
3127 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double click</b> a panned chart.
3131 <h4>Double Click</h4>
3132 Double Click a chart to reset all the charts to their default auto-refreshing state.
3136 <h4>SHIFT + Drag</h4>
3137 While pressing the shift key, click on the contents of a chart and move the mouse to select an area, to zoom in. The other charts will follow too. Zooming is performed in two phases:
3139 <li>The already loaded chart contents are zoomed (low resolution)</li>
3140 <li>New data are transferred from the netdata server, to refresh the chart with possibly more detail.</li>
3142 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
3146 <h4>SHIFT + Mouse Wheel</h4>
3147 While pressing the shift key and the mouse pointer is over the contents of a chart, scroll the mouse wheel to zoom in or out. This kind of zooming is aligned to center below the mouse pointer. The other charts will follow too.
3149 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
3153 <h4>Legend Operations</h4>
3154 Click on the label or value of a dimension, will select / un-select this dimension.
3156 You can press any of the SHIFT or CONTROL keys and then click on legend labels or values, to select / un-select multiple dimensions.
3159 <div role="tabpanel" class="tab-pane" id="help_touch">
3162 Single Tap on the contents of a chart to show, at its legend, the values for the timestamp tapped (the chart will also highlight the point at the chart).
3164 All the other visible charts will also show and highlight their values for the same timestamp.
3168 <h4>Drag Chart Contents</h4>
3169 Touch and Drag the contents of a chart to pan it horizontally.
3171 All the charts will follow soon after you let the chart alone (this little delay is by design: it speeds up your browser and lets you focus on what you are exploring).
3173 Once a chart is panned, auto refreshing stops for all charts. To enable it again, <b>double tap</b> a panned chart.
3178 Double tap a chart to reset all the charts to their default auto-refreshing state.
3182 <h4>Zoom <small>(does not work on firefox and IE/Edge)</small></h4>
3183 With two fingers, zoom in or out.
3185 Once a chart is zoomed, auto refreshing stops for all charts. To enable it again, <b>double click</b> a zoomed chart.
3189 <h4>Legend Operations</h4>
3190 Tap on the label or value of a dimension, will select / un-select this dimension.
3195 <div class="modal-footer">
3196 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3202 <div class="modal fade" id="alarmsModal" tabindex="-1" role="dialog" aria-labelledby="alarmsModalLabel">
3203 <div class="modal-dialog modal-lg" role="document" style="display: table;"> <!-- allow the modal to expand horizontally -->
3204 <div class="modal-content">
3205 <div class="modal-header">
3206 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3207 <h4 class="modal-title" id="alarmsModalLabel">netdata alarms</h4>
3209 <div class="modal-body">
3211 <ul class="nav nav-tabs" role="tablist">
3212 <li role="presentation" class="active"><a href="#alarms_active" aria-controls="alarms_active" role="tab" data-toggle="tab">Active</a></li>
3213 <li role="presentation"><a href="#alarms_all" aria-controls="alarms_all" role="tab" data-toggle="tab">All</a></li>
3214 <li role="presentation"><a href="#alarms_log" aria-controls="alarms_log" role="tab" data-toggle="tab">Log</a></li>
3218 <div class="tab-content">
3219 <div role="tabpanel" class="tab-pane active" id="alarms_active">
3222 <div role="tabpanel" class="tab-pane" id="alarms_all">
3225 <div role="tabpanel" class="tab-pane" id="alarms_log">
3230 <div class="modal-footer">
3231 <!-- <a href="#" onclick="alarmsUpdateModal(); return false;" type="button" class="btn btn-default">Update</a> -->
3232 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3238 <div class="modal fade" id="optionsModal" tabindex="-1" role="dialog" aria-labelledby="optionsModalLabel">
3239 <div class="modal-dialog modal-lg" role="document">
3240 <div class="modal-content">
3241 <div class="modal-header">
3242 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3243 <h4 class="modal-title" id="optionsModalLabel">netdata dashboard options</h4>
3245 <div class="modal-body">
3247 <small style="color: #BBBBBB;">These are browser settings. Each viewer has its own. They do not affect the operation of your netdata server.
3249 Settings take effect immediately and are saved permanently to browser local storage (except the refresh on focus / always option).
3251 To reset all options (including charts sizes) to their defaults, click <a href="#" onclick="resetDashboardOptions(); return false;">here</a>.</small>
3253 <div style="padding: 10px;"></div>
3256 <ul class="nav nav-tabs" role="tablist">
3257 <li role="presentation" class="active"><a href="#settings_performance" aria-controls="settings_performance" role="tab" data-toggle="tab">Performance</a></li>
3258 <li role="presentation"><a href="#settings_sync" aria-controls="settings_sync" role="tab" data-toggle="tab">Synchronization</a></li>
3259 <li role="presentation"><a href="#settings_visual" aria-controls="settings_visual" role="tab" data-toggle="tab">Visual</a></li>
3263 <div class="tab-content">
3264 <div role="tabpanel" class="tab-pane active" id="settings_performance">
3265 <form id="optionsForm1" method="get" class="form-horizontal">
3266 <div class="form-group">
3268 <tr class="option-row">
3269 <td class="option-control"><input id="stop_updates_when_focus_is_lost" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="On Focus" data-off="Always" data-width="110px"></td>
3270 <td class="option-info"><strong>When to refresh the charts?</strong><br/>
3271 <small>When set to <b>On Focus</b>, the charts will stop being updated if the page / tab does not have the focus of the user. When set to <b>Always</b>, the charts will always be refreshed. Set it to <b>On Focus</b> it to lower the CPU requirements of the browser (and extend the battery of laptops and tablets) when this page does not have your focus. Set to <b>Always</b> to work on another window (i.e. change the settings of something) and have the charts auto-refresh in this window.</small>
3274 <tr class="option-row">
3275 <td class="option-control">
3276 <input id="eliminate_zero_dimensions" type="checkbox" checked data-toggle="toggle" data-on="Non Zero" data-off="All" data-width="110px">
3278 <td class="option-info"><strong>Which dimensions to show?</strong><br/>
3279 <small>When set to <b>Non Zero</b>, dimensions that have all their values (within the current view) set to zero will not be transferred from the netdata server (except if all dimensions of the chart are zero, in which case this setting does nothing - all dimensions are transferred and shown). When set to <b>All</b>, all dimensions will always be shown. Set it to <b>Non Zero</b> to lower the data transferred between netdata and your browser, lower the CPU requirements of your browser (fewer lines to draw) and increase the focus on the legends (fewer entries at the legends).</small>
3282 <tr class="option-row">
3283 <td class="option-control"><input id="destroy_on_hide" type="checkbox" data-toggle="toggle" data-on="Destroy" data-off="Hide" data-width="110px"></td>
3284 <td class="option-info"><strong>How to handle hidden charts?</strong><br/>
3285 <small>When set to <b>Destroy</b>, charts that are not in the current viewport of the browser (are above, or below the visible area of the page), will be destroyed and re-created if and when they become visible again. When set to <b>Hide</b>, the not-visible charts will be just hidden, to simplify the DOM and speed up your browser. Set it to <b>Destroy</b>, to lower the memory requirements of your browser. Set it to <b>Hide</b> for faster restoration of charts on page scrolling.</small>
3288 <tr class="option-row">
3289 <td class="option-control"><input id="async_on_scroll" type="checkbox" data-toggle="toggle" data-on="Async" data-off="Sync" data-width="110px"></td>
3290 <td class="option-info"><strong>Page scroll handling?</strong><br/>
3291 <small>When set to <b>Sync</b>, charts will be examined for their visibility synchronously. On slow computers this may impact the smoothness of page scrolling. To work asynchronously set it to <b>Async</b>. When set to <b>Sync</b>, the performance of page scrolling is monitored and this setting switches automatically to <b>Async</b> if the browser is found slow. Set it to <b>Sync</b> for best visual experience. Set it to <b>Async</b> for smoother page scrolling.</small>
3298 <div role="tabpanel" class="tab-pane" id="settings_sync">
3299 <form id="optionsForm2" method="get" class="form-horizontal">
3300 <div class="form-group">
3302 <tr class="option-row">
3303 <td class="option-control"><input id="parallel_refresher" type="checkbox" checked data-toggle="toggle" data-on="Parallel" data-off="Sequential" data-width="110px"></td>
3304 <td class="option-info"><strong>Which chart refresh policy to use?</strong><br/>
3305 <small>When set to <b>parallel</b>, visible charts are refreshed in parallel (all queries are sent to netdata server in parallel) and are rendered asynchronously. When set to <b>sequential</b> charts are refreshed one after another. Set it to parallel if your browser can cope with it (most modern browsers do), set it to sequential if you work on an older/slower computer.</small>
3308 <tr class="option-row" id="concurrent_refreshes_row">
3309 <td class="option-control"><input id="concurrent_refreshes" type="checkbox" checked data-toggle="toggle" data-on="Resync" data-off="Best Effort" data-width="110px"></td>
3310 <td class="option-info"><strong>Shall we re-sync chart refreshes?</strong><br/>
3311 <small>When set to <b>Resync</b>, the dashboard will attempt to re-synchronize all the charts so that they are refreshed concurrently. When set to <b>Best Effort</b>, each chart may be refreshed with a little time difference to the others. Normally, the dashboard starts refreshing them in parallel, but depending on the speed of your computer and the network latencies, charts start having a slight time difference. Setting this to <b>Resync</b> will attempt to re-synchronize the charts on every update. Setting it to <b>Best Effort</b> may lower the pressure on your browser and the network.</small>
3314 <tr class="option-row">
3315 <td class="option-control"><input id="sync_selection" type="checkbox" checked data-toggle="toggle" data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td>
3316 <td class="option-info"><strong>Sync hover selection on all charts?</strong><br/>
3317 <small>When enabled, a selection on one chart will automatically select the same time on all other visible charts and the legends of all visible charts will be updated to show the selected values. When disabled, only the chart getting the user's attention will be selected. Enable it to get better insights of the data. Disable it if you are on a very slow computer that cannot actually do it.</small>
3320 <tr class="option-row">
3321 <td class="option-control"><input id="sync_pan_and_zoom" type="checkbox" checked data-toggle="toggle" data-on="Sync" data-off="Don't Sync" data-onstyle="success" data-offstyle="danger" data-width="110px"></td>
3322 <td class="option-info"><strong>Sync pan and zoom on all charts?</strong><br/>
3323 <small>When enabled, pan and zoom operations on a chart will be replicated to all charts (even the ones that are not currently visible - of course only when they will become visible). When disabled, pan and zoom operations will not be propagated to other charts.</small>
3330 <div role="tabpanel" class="tab-pane" id="settings_visual">
3331 <form id="optionsForm3" method="get" class="form-horizontal">
3332 <div class="form-group">
3334 <tr class="option-row">
3335 <td class="option-control"><input id="netdata_theme_control" type="checkbox" checked data-toggle="toggle" data-offstyle="danger" data-onstyle="success" data-on="Dark" data-off="White" data-width="110px"></td>
3336 <td class="option-info"><strong>Which theme to use?</strong><br/>
3337 <small>Netdata comes with two themes: <b>Dark</b> (the default) and <b>White</b>.
3339 <b>Switching this will reload the dashboard</b>.
3343 <tr class="option-row">
3344 <td class="option-control"><input id="show_help" type="checkbox" checked data-toggle="toggle" data-on="Help Me" data-off="No Help" data-width="110px"></td>
3345 <td class="option-info"><strong>Do you need help?</strong><br/>
3346 <small>Netdata can show some help in some areas to help you use the dashboard. If all these balloons bother you, disable them using this switch.
3348 <b>Switching this will reload the dashboard</b>.
3352 <tr class="option-row">
3353 <td class="option-control"><input id="pan_and_zoom_data_padding" type="checkbox" checked data-toggle="toggle" data-on="Pad" data-off="Don't Pad" data-width="110px"></td>
3354 <td class="option-info"><strong>Enable data padding when panning and zooming?</strong><br/>
3355 <small>When set to <b>Pad</b> the charts will be padded with more data, both before and after the visible area, thus giving the impression the whole database is loaded. This padding will happen only after the first pan or zoom operation on the chart (initially all charts have only the visible data). When set to <b>Don't Pad</b> only the visible data will be transfered from the netdata server, even after the first pan and zoom operation.</small>
3358 <tr class="option-row">
3359 <td class="option-control"><input id="smooth_plot" type="checkbox" checked data-toggle="toggle" data-on="Smooth" data-off="Rough" data-width="110px"></td>
3360 <td class="option-info"><strong>Enable Bézier lines on charts?</strong><br/>
3361 <small>When set to <b>Smooth</b> the charts libraries that support it, will plot smooth curves instead of simple straight lines to connect the points.
3363 Keep in mind <a href="http://dygraphs.com" target="_blank">dygraphs</a>, the main charting library in netdata dashboards, can only smooth line charts. It cannot smooth area or stacked charts. When set to <b>Rough</b>, this setting can lower the CPU resources consumed by your browser.</small>
3372 <div class="modal-footer">
3373 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3380 <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel">
3381 <div class="modal-dialog" role="document">
3382 <div class="modal-content">
3383 <div class="modal-header">
3384 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3385 <h4 class="modal-title" id="updateModalLabel">Update Check</h4>
3387 <div class="modal-body">
3388 Your netdata version: <b><code><span id="netdataVersion">Unknown</span></code></b><br/>
3389 Your netdata commit: <b><code><span id="netdataCommitId">Unknown</span></code></b>
3391 <div style="padding: 10px;"></div>
3392 <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
3397 For progress reports and key netdata updates: <strong><a href="https://twitter.com/linuxnetdata" target="_blank">follow netdata on <i class="fa fa-twitter" aria-hidden="true"></i> twitter</a></strong>.
3400 You can also <a href="https://www.facebook.com/linuxnetdata/" target="_blank">follow netdata on <i class="fa fa-facebook" aria-hidden="true"></i> facebook</a>,
3401 or <a href="https://github.com/firehol/netdata" target="_blank">watch netdata on <i class="fa fa-github" aria-hidden="true"></i> github</a>.
3405 <div class="modal-footer">
3406 <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
3407 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3413 <div class="modal fade" id="deleteRegistryModal" tabindex="-1" role="dialog" aria-labelledby="deleteRegistryModalLabel">
3414 <div class="modal-dialog" role="document">
3415 <div class="modal-content">
3416 <div class="modal-header">
3417 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3418 <h4 class="modal-title" id="deleteRegistryModalLabel">Delete <span id="deleteRegistryServerName"></span>?</h4>
3420 <div class="modal-body">
3421 You are about to delete, from your personal list of netdata servers, the following server:
3422 <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3423 <b><span id="deleteRegistryServerName2"></span></b>
3425 <b><span id="deleteRegistryServerURL"></span></b>
3427 Are you sure you want to do this?
3429 <div style="padding: 10px;"></div>
3430 <small>Keep in mind, this server will be added back if and when you visit it again.</small>
3432 <div id="deleteRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3434 <div class="modal-footer">
3435 <button type="button" class="btn btn-success" data-dismiss="modal">keep it</button>
3436 <a href="#" onclick="notifyForDeleteRegistry(true); return false;" type="button" class="btn btn-danger">delete it</a>
3442 <div class="modal fade" id="switchRegistryModal" tabindex="-1" role="dialog" aria-labelledby="switchRegistryModalLabel">
3443 <div class="modal-dialog" role="document">
3444 <div class="modal-content">
3445 <div class="modal-header">
3446 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3447 <h4 class="modal-title" id="switchRegistryModalLabel">Switch Netdata Registry Identity</h4>
3449 <div class="modal-body">
3450 You can copy and paste the following ID to all your browsers (e.g. work and home).
3452 All the browsers with the same ID will identify <b>you</b>, so please don't share this with others.
3453 <p style="text-align: center; padding-top: 10px; padding-bottom: 10px; line-height: 2;">
3455 <input type="text" class="form-control" id="switchRegistryPersonGUID" placeholder="your personal ID" maxlength="36" autocomplete="off" style="text-align: center; font-size: 1.4em;">
3458 Either copy this ID and paste it to another browser, or paste here the ID you have taken from another browser.
3459 <p style="padding-top: 10px;"><small>
3462 <li>when you switch ID, your previous ID will be lost forever - this is irreversible.</li>
3463 <li>both IDs (your old and the new) must list this netdata at their personal lists.</li>
3464 <li>both IDs have to be known by the registry: <b><span id="switchRegistryURL"></span></b>.</li>
3465 <li>to get a new ID, just clear your browser cookies.</li>
3468 <div id="switchRegistryResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3470 <div class="modal-footer">
3471 <button type="button" class="btn btn-success" data-dismiss="modal">cancel</button>
3472 <a href="#" onclick="notifyForSwitchRegistry(true); return false;" type="button" class="btn btn-danger">impersonate</a>
3478 <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
3479 <div class="modal-dialog" role="document">
3480 <div class="modal-content">
3481 <div class="modal-header">
3482 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
3483 <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
3485 <div class="modal-body">
3486 Checking known URLs for this server...
3487 <div style="padding-top: 20px;">
3488 <table id="gotoServerList">
3491 <p style="padding-top: 10px;"><small>
3492 Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
3494 <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
3496 <div class="modal-footer">
3497 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
3504 <script type="text/javascript" src="dashboard.js?v20170211-2"></script>