]> arthur.barton.de Git - netdata.git/blobdiff - web/index.html
Merge remote-tracking branch 'upstream/master' into health
[netdata.git] / web / index.html
index cb92af5ab791d3d5148674dc8b6ebda74d9113bc..59629ae1cf4888d7dbab6a985810221200f85b6a 100644 (file)
@@ -2,6 +2,7 @@
 <html lang="en">
 <head>
        <title>netdata dashboard</title>
+       <meta name="application-name" content="netdata">
 
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta charset="utf-8">
                padding-top: 50px;
        }
 
+       .loadOverlay {
+               position: absolute;
+               top: 0px;
+               left: 0px;
+               width: 100%;
+               height:100%;
+               z-index: 2000;
+               font-size: 10vh;
+               font-family: sans-serif;
+               padding: 40vh 0 40vh 0;
+               font-weight: bold;
+               text-align: center;
+       }
+
        .modal-wide .modal-dialog {
                width: 80%;
        }
        }
        </style>
 
-       <!-- you can set your netdata server globally, by ucommenting this -->
-       <!-- you can also give a different server per chart, with the attribute: data-host="http://netdata.server:19999" -->
-       <!-- <script> netdataServer = "http://box:19999"; </script> -->
-
        <!-- check which theme to use -->
-       <script>
+       <script type="text/javascript">
+               // --------------------------------------------------------------------
+               // urlOptions
+
+               var urlOptions = {
+                       hash: '#',
+                       theme: null,
+                       help: null,
+                       pan_and_zoom: false,
+                       after: 0,
+                       before: 0,
+                       nowelcome: 0,
+                       hasProperty: function(property) {
+                               // console.log('checking property ' + property + ' of type ' + typeof(this[property]));
+                               return typeof this[property] !== 'undefined';
+                       }
+               };
+
+               function netdataPanAndZoomCallback(status, after, before) {
+                       urlOptions.pan_and_zoom = status;
+                       urlOptions.after = after;
+                       urlOptions.before = before;
+                       netdataHashUpdate();
+               }
+
+               function netdataHashUpdate() {
+                       history.replaceState(null, document.title, netdataHash());
+               }
+
+               function netdataHash() {
+                       var hash = urlOptions.hash;
+
+                       if(urlOptions.pan_and_zoom === true) {
+                               hash += ';after='  + urlOptions.after.toString() +
+                                       ';before=' + urlOptions.before.toString();
+                       }
+
+                       if(urlOptions.theme !== null)
+                               hash += ';theme=' + urlOptions.theme.toString();
+
+                       if(urlOptions.help !== null)
+                               hash += ';help=' + urlOptions.help.toString();
+
+                       return hash;
+               }
+
+               function netdataHashParse() {
+                       var variables = document.location.hash.split(';');
+                       var len = variables.length;
+                       while(len--) {
+                               if(len !== 0) {
+                                       var p = variables[len].split('=');
+                                       if(urlOptions.hasProperty(p[0]) && typeof p[1] !== 'undefined')
+                                               urlOptions[p[0]] = p[1];
+                               }
+                               else {
+                                       if(variables[len].length > 0)
+                                               urlOptions.hash = variables[len];
+                               }
+                       }
+
+                       if(urlOptions.before > 0 && urlOptions.after > 0)
+                               urlOptions.pan_and_zoom = true;
+
+                       // console.log(urlOptions);
+               }
+
+               netdataHashParse();
+
+               // --------------------------------------------------------------------
+               // check options that should be processed before loading netdata.js
+               
                function loadLocalStorage(name) {
                        var ret = null;
 
                        if(typeof ret === 'undefined' || ret === null)
                                return null;
 
+                       // console.log('loaded: ' + name.toString() + ' = ' + ret.toString());
+
                        return ret;
                }
 
                function saveLocalStorage(name, value) {
+                       // console.log('saving: ' + name.toString() + ' = ' + value.toString());
                        try {
                                if(typeof Storage !== "undefined" && typeof localStorage === 'object') {
                                        localStorage.setItem(name, value.toString());
                                return ret;
                }
 
-               var netdataTheme = getTheme('slate');
-
                function setTheme(theme) {
                        if(theme === netdataTheme) return false;
-
                        return saveLocalStorage('netdataTheme', theme);
                }
 
+               var netdataTheme = getTheme('slate');
+               var netdataShowHelp = true;
+
+               if(urlOptions.theme !== null) {
+                       setTheme(urlOptions.theme);
+                       netdataTheme = urlOptions.theme;
+               }
+               else
+                       urlOptions.theme = netdataTheme;
+
+               if(urlOptions.help !== null) {
+                       saveLocalStorage('options.show_help', urlOptions.help);
+                       netdataShowHelp = urlOptions.help;
+               }
+               else {
+                       urlOptions.help = loadLocalStorage('options.show_help');
+               }
+
+               // --------------------------------------------------------------------
+               // registry call back to render my-netdata menu
+
                var netdataRegistryCallback = function(machines_array) {
                        var el = '';
                        var a1 = '';
                                while(len--) {
                                        var u = machines[len];
                                        found++;
-                                       el += '<li id="registry_server_' + u.guid + '"><a href="#" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>';
+                                       el += '<li id="registry_server_' + u.guid + '"><a class="registry_link" href="' + u.url + '" onClick="return gotoServerModalHandler(\'' + u.guid + '\');">' + u.name + '</a></li>';
                                        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>';
                                }
                        }
                        document.getElementById('mynetdata_servers').innerHTML = el;
                        document.getElementById('mynetdata_servers2').innerHTML = el;
                        document.getElementById('mynetdata_actions1').innerHTML = a1;
+
+                       gotoServerInit();
                };
 
        </script>
 
        <!-- load the dashboard manager - it will do the rest -->
-       <script type="text/javascript" src="dashboard.js?v39"></script>
+       <script type="text/javascript" src="dashboard.js?v41"></script>
 </head>
-
 <body data-spy="scroll" data-target="#sidebar">
+       <div id="loadOverlay" class="loadOverlay" style="background-color: #888; color: #888;">
+               netdata<br/><div style="font-size: 3vh;">Real-time performance monitoring, done right!</div>
+       </div>
+       <script type="text/javascript">
+               // change the loadOverlay colors ASAP to match the theme
+               document.getElementById('loadOverlay').style = (urlOptions.theme === 'slate')?"background-color:#272b30; color: #373b40;":"background-color:#fff; color: #ddd;";
+       </script>
        <nav class="navbar navbar-default navbar-fixed-top" role="banner">
                <div class="container">
                        <nav id="mynetdata_nav" class="collapse navbar-collapse navbar-left hidden-sm hidden-xs" role="navigation" style="padding-right: 20px;">
                </div>
        </div>
 
-<script>
+<script type="text/javascript">
 var this_is_demo = null;
 function isdemo() {
        if(this_is_demo !== null) return this_is_demo;
@@ -1018,7 +1129,34 @@ function isdemo() {
 if(isdemo()) {
        document.getElementById('masthead').style.display = 'block';
 }
+
+function netdataURL(url) {
+       if(typeof url === 'undefined')
+               url = document.location.toString();
+
+       if(url.indexOf('#') !== -1)
+               url = url.substring(0, url.indexOf('#'));
+
+       var hash = netdataHash();
+
+       // console.log('netdataURL: ' + url + hash);
+
+       return url + hash;
+}
+
+function netdataReload(url) {
+       var t = netdataURL(url);
+       // console.log('netdataReload: ' + t);
+       document.location = t;
+
+       // since we play with hash
+       // this is needed to reload the page
+       location.reload();
+}
+
 var gotoServerValidateRemaining = 0;
+var gotoServerMiddleClick = false;
+var gotoServerStop = false;
 function gotoServerValidateUrl(id, guid, url) {
        var penaldy = 0;
        if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://'))
@@ -1026,27 +1164,44 @@ function gotoServerValidateUrl(id, guid, url) {
                        // to allow the user walk through all its servers.
                        penaldy = 500;
 
+       var finalURL = netdataURL(url);
+
        setTimeout(function() {
-               document.getElementById('gotoServerList').innerHTML += '<tr><td style="padding-left: 20px;"><a href="' + url + '" target="_blank">' + url + '</a></td><td style="padding-left: 30px;"><code id="' + guid + '-' + id + '-status">checking...</code></td></tr>';
+               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>';
+
                NETDATA.registry.hello(url, function(data) {
                        if (data) {
-                               console.log('OK ' + id + ' URL: ' + url);
+                               // console.log('OK ' + id + ' URL: ' + url);
                                document.getElementById(guid + '-' + id + '-status').innerHTML = "OK";
-                               document.location = url;
+
+                               if(!gotoServerStop) {
+                                       gotoServerStop = true;
+
+                                       if(gotoServerMiddleClick) {
+                                               window.open(finalURL, '_blank');
+                                               gotoServerMiddleClick = false;
+                                               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)';
+                                       }
+                                       else
+                                               document.location = finalURL;
+                               }
                        }
                        else {
                                document.getElementById(guid + '-' + id + '-status').innerHTML = "failed!";
                                gotoServerValidateRemaining--;
-                               if(gotoServerValidateRemaining <= 0)
+                               if(gotoServerValidateRemaining <= 0) {
+                                       gotoServerMiddleClick = false;
                                        document.getElementById('gotoServerResponse').innerHTML = '<b>Sorry! I cannot find any operational URL for this server</b>';
+                               }
                        }
                });
        }, (id * 50) + penaldy);
 }
 
 function gotoServerModalHandler(guid) {
-       console.log('goto server: ' + guid);
+       // console.log('goto server: ' + guid);
 
+       gotoServerStop = false;
        var len = NETDATA.registry.machines[guid].alternate_urls.length;
 
        document.getElementById('gotoServerResponse').innerHTML = '';
@@ -1061,6 +1216,20 @@ function gotoServerModalHandler(guid) {
        return false;
 }
 
+function gotoServerInit() {
+       $(".registry_link").on('click', function(e) {
+               if(e.which === 2) {
+                       e.preventDefault();
+                       gotoServerMiddleClick = true;
+               }
+               else {
+                       gotoServerMiddleClick = false;
+               }
+
+               return true;
+       });
+}
+
 function switchRegistryModalHandler() {
        document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid;
        document.getElementById('switchRegistryURL').innerHTML = NETDATA.registry.server;
@@ -1124,7 +1293,7 @@ var options = {
        chartsPerRow: 0,
        chartsMinWidth: 1450,
        chartsHeight: 180,
-       sparklinesHeight: 60
+       sparklinesHeight: 60,
 };
 
 // generate a sparkline
@@ -1184,6 +1353,21 @@ function sortObjectByPriority(object) {
        return sorted;
 }
 
+
+// ----------------------------------------------------------------------------
+// scroll to a section, without changing the browser history
+
+function scrollToId(hash) {
+       if(hash && hash != '') {
+               var offset = $('#' + hash).offset();
+               if(typeof offset !== 'undefined')
+                       $('html, body').animate({ scrollTop: offset.top }, 0);
+       }
+
+       // we must return false to prevent the default action
+       return false;
+}
+
 // ----------------------------------------------------------------------------
 
 function gaugeChart(title, width, dimensions, colors) {
@@ -1276,19 +1460,19 @@ var menuData = {
 
        'apps': {
                title: 'Applications',
-               info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported).<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+               info: 'Per application statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics for applications of interest, defined in <code>/etc/netdata/apps_groups.conf</code> (the default is <a href="https://github.com/firehol/netdata/blob/master/conf.d/apps_groups.conf" target="_blank">here</a>). The plugin internally builds a process tree (much like <code>ps fax</code> does), and groups processes together (evaluating both child and parent processes) so that the result is always a chart with a predefined set of dimensions (of course, only application groups found running are reported). The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
                height: 1.5
        },
 
        'users': {
                title: 'Users',
-               info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+               info: 'Per user statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
                height: 1.5
        },
 
        'groups': {
                title: 'User Groups',
-               info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group.<br/><b>IMPORTANT</b>: The values shown here are not 100% accurate. They only include values for the processes running. If an application is spawning children continuously, which are terminated in just a few milliseconds (like shell scripts do), the values reported will be inaccurate. Linux does report the values for the exited children of a process. However, these values are reported to the parent process <b>only when the child exits</b>. If these values, of the exited child processes, were also aggregated in the charts below, the charts would have been full of spikes, presenting unrealistic utilization for each process group. So, we decided to ignore these values and present only the utilization of <b>the currently running processes</b>.',
+               info: 'Per user group statistics are collected using netdata\'s <code>apps.plugin</code>. This plugin walks through the entire <code>/proc</code> filesystem and aggregates statistics per user group. The reported values are compatible with <code>top</code>, although the netdata plugin counts also the resources of exited children (unlike <code>top</code> which shows only the resources of the currently running processes). So for processes like shell scripts, the reported values include the resources used by the commands these scripts run within each timeframe.',
                height: 1.5
        },
 
@@ -1307,15 +1491,45 @@ var menuData = {
                info: undefined
        },
 
+       'memcached': {
+               title: 'memcached',
+               info: undefined
+       },
+
        'mysql': {
                title: 'MySQL',
                info: undefined
        },
 
+       'redis': {
+               title: 'Redis',
+               info: undefined
+       },
+
+       'ipfs': {
+               title: 'IPFS',
+               info: undefined
+       },
+
+       'phpfpm': {
+               title: 'PHP-FPM',
+               info: undefined,
+       },
+
+       'nginx': {
+               title: 'nginx',
+               info: undefined,
+       },
+
+       'apache': {
+               title: 'Apache',
+               info: undefined,
+       },
+
        'named': {
                title: 'named',
                info: undefined
-       },
+       }
 };
 
 var submenuData = {
@@ -1340,53 +1554,23 @@ var submenuData = {
        }
 };
 
+//
+// chartData works on the context of a chart
+// Its purpose is to set:
+//
+// info: the text above the charts
+// heads: the representation of the chart at the top the subsection (second level menu)
+// mainheads: the representation of the chart at the top of the section (first level menu)
+// colors: the dimension colors of the chart (the default colors are appended)
+// height: the ratio of the chart height relative to the default
+//
 var chartData = {
-       'mysql.net': {
-               info: 'The amount of data sent to mysql clients (<strong>out</strong>) and received from mysql clients (<strong>in</strong>).'
-       },
-
-       'mysql.queries': {
-               info: 'The number of statements executed by the server.<ul>' +
-               '<li><strong>queries</strong> counts the statements executed within stored SQL programs.</li>' +
-               '<li><strong>questions</strong> counts the statements sent to the mysql server by mysql clients.</li>' +
-               '<li><strong>slow queries</strong> counts the number of statements that took more than <a href="http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_long_query_time" target="_blank">long_query_time</a> seconds to be executed.' +
-               ' For more information about slow queries check the mysql <a href="http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html" target="_blank">slow query log</a>.</li>' +
-               '</ul>'
-       },
-
-       'mysql.handlers': {
-               info: 'Usage of the internal handlers of mysql. This chart provides very good insights of what the mysql server is actually doing.' +
-               ' (if the chart is not showing all these dimensions it is because they are zero - set <strong>Which dimensions to show?</strong> to <strong>All</strong> from the dashboard settings, to render even the zero values)<ul>' +
-               '<li><strong>commit</strong>, the number of internal <a href="http://dev.mysql.com/doc/refman/5.7/en/commit.html" target="_blank">COMMIT</a> statements.</li>' +
-               '<li><strong>delete</strong>, the number of times that rows have been deleted from tables.</li>' +
-               '<li><strong>prepare</strong>, a counter for the prepare phase of two-phase commit operations.</li>' +
-               '<li><strong>read first</strong>, the number of times the first entry in an index was read. A high value suggests that the server is doing a lot of full index scans; e.g. <strong>SELECT col1 FROM foo</strong>, with col1 indexed.</li>' +
-               '<li><strong>read key</strong>, the number of requests to read a row based on a key. If this value is high, it is a good indication that your tables are properly indexed for your queries.</li>' +
-               '<li><strong>read next</strong>, the number of requests to read the next row in key order. This value is incremented if you are querying an index column with a range constraint or if you are doing an index scan.</li>' +
-               '<li><strong>read prev</strong>, the number of requests to read the previous row in key order. This read method is mainly used to optimize <strong>ORDER BY ... DESC</strong>.</li>' +
-               '<li><strong>read rnd</strong>, the number of requests to read a row based on a fixed position. A high value indicates you are doing a lot of queries that require sorting of the result. You probably have a lot of queries that require MySQL to scan entire tables or you have joins that do not use keys properly.</li>' +
-               '<li><strong>read rnd next</strong>, the number of requests to read the next row in the data file. This value is high if you are doing a lot of table scans. Generally this suggests that your tables are not properly indexed or that your queries are not written to take advantage of the indexes you have.</li>' +
-               '<li><strong>rollback</strong>, the number of requests for a storage engine to perform a rollback operation.</li>' +
-               '<li><strong>savepoint</strong>, the number of requests for a storage engine to place a savepoint.</li>' +
-               '<li><strong>savepoint rollback</strong>, the number of requests for a storage engine to roll back to a savepoint.</li>' +
-               '<li><strong>update</strong>, the number of requests to update a row in a table.</li>' +
-               '<li><strong>write</strong>, the number of requests to insert a row in a table.</li>' +
-               '</ul>'
-       },
-
-       'mysql.table_locks': {
-               info: 'MySQL table locks counters: <ul>' +
-               '<li><strong>immediate</strong>, the number of times that a request for a table lock could be granted immediately.</li>' +
-               '<li><strong>waited</strong>, the number of times that a request for a table lock could not be granted immediately and a wait was needed. If this is high and you have performance problems, you should first optimize your queries, and then either split your table or tables or use replication.</li>' +
-               '</ul>'
-       },
-
        'system.cpu': {
                info: 'Total CPU utilization (all cores). 100% here means there is no CPU idle time at all. You can get per core usage at the <a href="#cpu">CPUs</a> section and per application usage at the <a href="#apps">Applications Monitoring</a> section.<br/>Keep an eye on <b>iowait</b> ' + sparkline('system.cpu', 'iowait', '%') + '. If it is constantly high, your disks are a bottleneck and they slow your system down.<br/>Another important metric worth monitoring, is <b>softirq</b> ' + sparkline('system.cpu', 'softirq', '%') + '. A constantly high percentage of softirq may indicate network drivers issues.'
        },
 
        'system.load': {
-               info: 'Current system load read from <code>/proc/loadavg</code>.',
+               info: 'Current system load, a measurement of the work the system is performing. A completely idle computer has a load average of 0. Each process either using or waiting for system resources (e.g. CPU, disk) adds 1 to the load average. So, if your system has a load of 5, five processes are either using or waiting for system resources. Linux calculates this once every 5 seconds. Netdata reads it from <code>/proc/loadavg</code>. For more information see: <a href="http://www.howtogeek.com/194642/understanding-the-load-average-on-linux-and-other-unix-like-systems/" target="_blank">this article</a>',
                height: 0.7
        },
 
@@ -1458,6 +1642,9 @@ var chartData = {
                info: 'System swap memory, read from <code>/proc/meminfo</code>.'
        },
 
+       // ------------------------------------------------------------------------
+       // MEMORY
+
        'mem.ksm_savings': {
                heads: [
                        gaugeChart('Saved', '12%', 'savings', '#0099CC')
@@ -1486,6 +1673,9 @@ var chartData = {
                colors: NETDATA.colors[3]
        },
 
+       // ------------------------------------------------------------------------
+       // APPS
+
        'apps.cpu': {
                height: 2.0
        },
@@ -1498,6 +1688,9 @@ var chartData = {
                height: 2.0
        },
 
+       // ------------------------------------------------------------------------
+       // USERS
+
        'users.cpu': {
                height: 2.0
        },
@@ -1510,6 +1703,9 @@ var chartData = {
                height: 2.0
        },
 
+       // ------------------------------------------------------------------------
+       // GROUPS
+
        'groups.cpu': {
                height: 2.0
        },
@@ -1522,6 +1718,9 @@ var chartData = {
                height: 2.0
        },
 
+       // ------------------------------------------------------------------------
+       // NETWORK QoS
+
        'tc.qos': {
                heads: [
                        function(id) {
@@ -1533,6 +1732,9 @@ var chartData = {
                ]
        },
 
+       // ------------------------------------------------------------------------
+       // NETWORK INTERFACES
+
        'net.net': {
                heads: [
                        gaugeChart('Received', '12%', 'received'),
@@ -1540,6 +1742,25 @@ var chartData = {
                ]
        },
 
+       // ------------------------------------------------------------------------
+       // NETFILTER
+
+       'netfilter.sockets': {
+               colors: '#88AA00',
+               heads: [
+                       gaugeChart('Active Connections', '12%', '', '#88AA00')
+               ]
+       },
+
+       'netfilter.new': {
+               heads: [
+                       gaugeChart('New Connections', '12%', 'new', '#5555AA')
+               ]
+       },
+
+       // ------------------------------------------------------------------------
+       // DISKS
+
        'disk.util': {
                colors: '#FF5588',
                heads: [
@@ -1569,19 +1790,6 @@ var chartData = {
                info: 'I/O operations currently in progress. This metric is a snapshot - it is not an average over the last interval.'
        },
 
-       'netfilter.sockets': {
-               colors: '#88AA00',
-               heads: [
-                       gaugeChart('Active Connections', '12%', '', '#88AA00')
-               ]
-       },
-
-       'netfilter.new': {
-               heads: [
-                       gaugeChart('New Connections', '12%', 'new', '#5555AA')
-               ]
-       },
-
        'disk.iotime': {
                height: 0.5,
                info: 'The sum of the duration of all completed I/O operations. This number can exceed the interval if the disk is able to execute I/O operations in parallel.'
@@ -1609,6 +1817,53 @@ var chartData = {
        'disk.inodes': {
                info: 'inodes (or index nodes) are filesystem objects (e.g. files and directories). On many types of file system implementations, the maximum number of inodes is fixed at filesystem creation, limiting the maximum number of files the filesystem can hold. It is possible for a device to run out of inodes. When this happens, new files cannot be created on the device, even though there may be free space available.'
        },
+
+       'mysql.net': {
+               info: 'The amount of data sent to mysql clients (<strong>out</strong>) and received from mysql clients (<strong>in</strong>).'
+       },
+
+       // ------------------------------------------------------------------------
+       // MYSQL
+
+       'mysql.queries': {
+               info: 'The number of statements executed by the server.<ul>' +
+               '<li><strong>queries</strong> counts the statements executed within stored SQL programs.</li>' +
+               '<li><strong>questions</strong> counts the statements sent to the mysql server by mysql clients.</li>' +
+               '<li><strong>slow queries</strong> counts the number of statements that took more than <a href="http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_long_query_time" target="_blank">long_query_time</a> seconds to be executed.' +
+               ' For more information about slow queries check the mysql <a href="http://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html" target="_blank">slow query log</a>.</li>' +
+               '</ul>'
+       },
+
+       'mysql.handlers': {
+               info: 'Usage of the internal handlers of mysql. This chart provides very good insights of what the mysql server is actually doing.' +
+               ' (if the chart is not showing all these dimensions it is because they are zero - set <strong>Which dimensions to show?</strong> to <strong>All</strong> from the dashboard settings, to render even the zero values)<ul>' +
+               '<li><strong>commit</strong>, the number of internal <a href="http://dev.mysql.com/doc/refman/5.7/en/commit.html" target="_blank">COMMIT</a> statements.</li>' +
+               '<li><strong>delete</strong>, the number of times that rows have been deleted from tables.</li>' +
+               '<li><strong>prepare</strong>, a counter for the prepare phase of two-phase commit operations.</li>' +
+               '<li><strong>read first</strong>, the number of times the first entry in an index was read. A high value suggests that the server is doing a lot of full index scans; e.g. <strong>SELECT col1 FROM foo</strong>, with col1 indexed.</li>' +
+               '<li><strong>read key</strong>, the number of requests to read a row based on a key. If this value is high, it is a good indication that your tables are properly indexed for your queries.</li>' +
+               '<li><strong>read next</strong>, the number of requests to read the next row in key order. This value is incremented if you are querying an index column with a range constraint or if you are doing an index scan.</li>' +
+               '<li><strong>read prev</strong>, the number of requests to read the previous row in key order. This read method is mainly used to optimize <strong>ORDER BY ... DESC</strong>.</li>' +
+               '<li><strong>read rnd</strong>, the number of requests to read a row based on a fixed position. A high value indicates you are doing a lot of queries that require sorting of the result. You probably have a lot of queries that require MySQL to scan entire tables or you have joins that do not use keys properly.</li>' +
+               '<li><strong>read rnd next</strong>, the number of requests to read the next row in the data file. This value is high if you are doing a lot of table scans. Generally this suggests that your tables are not properly indexed or that your queries are not written to take advantage of the indexes you have.</li>' +
+               '<li><strong>rollback</strong>, the number of requests for a storage engine to perform a rollback operation.</li>' +
+               '<li><strong>savepoint</strong>, the number of requests for a storage engine to place a savepoint.</li>' +
+               '<li><strong>savepoint rollback</strong>, the number of requests for a storage engine to roll back to a savepoint.</li>' +
+               '<li><strong>update</strong>, the number of requests to update a row in a table.</li>' +
+               '<li><strong>write</strong>, the number of requests to insert a row in a table.</li>' +
+               '</ul>'
+       },
+
+       'mysql.table_locks': {
+               info: 'MySQL table locks counters: <ul>' +
+               '<li><strong>immediate</strong>, the number of times that a request for a table lock could be granted immediately.</li>' +
+               '<li><strong>waited</strong>, the number of times that a request for a table lock could not be granted immediately and a wait was needed. If this is high and you have performance problems, you should first optimize your queries, and then either split your table or tables or use replication.</li>' +
+               '</ul>'
+       },
+
+       // ------------------------------------------------------------------------
+       // APACHE
+
        'apache.connections': {
                colors: NETDATA.colors[4],
                mainheads: [
@@ -1619,7 +1874,7 @@ var chartData = {
        'apache.requests': {
                colors: NETDATA.colors[0],
                mainheads: [
-                       gaugeChart('Connections', '12%', '', NETDATA.colors[0])
+                       gaugeChart('Requests', '12%', '', NETDATA.colors[0])
                ]
        },
 
@@ -1665,6 +1920,10 @@ var chartData = {
                height: 0.5
        },
 
+
+       // ------------------------------------------------------------------------
+       // NGINX
+
        'nginx.connections': {
                colors: NETDATA.colors[4],
                mainheads: [
@@ -1750,9 +2009,20 @@ function enrichChartData(chart) {
                        chart.menu = tmp;
                        break;
 
+               case 'apache':
+               case 'cgroup':
+               case 'exim':
+               case 'memcached':
                case 'mysql':
                case 'named':
-               case 'cgroup':
+               case 'nginx':
+               case 'phpfpm':
+               case 'postfix':
+               case 'redis':
+               case 'ipfs':
+               case 'squid':
+               case 'snmp':
+               case 'tomcat':
                        chart.menu = chart.type;
                        chart.menu_pattern = tmp;
                        break;
@@ -1823,7 +2093,6 @@ function headMain(charts, duration) {
                + ' data-dimensions="in"'
                + ' data-chart-library="easypiechart"'
                + ' data-title="Disk Read"'
-               + ' data-units="KB / s"'
                + ' data-width="10%"'
                + ' data-before="0"'
                + ' data-after="-' + duration.toString() + '"'
@@ -1834,7 +2103,6 @@ function headMain(charts, duration) {
                + ' data-dimensions="out"'
                + ' data-chart-library="easypiechart"'
                + ' data-title="Disk Write"'
-               + ' data-units="KB / s"'
                + ' data-width="10%"'
                + ' data-before="0"'
                + ' data-after="-' + duration.toString() + '"'
@@ -1859,7 +2127,6 @@ function headMain(charts, duration) {
                + ' data-dimensions="received"'
                + ' data-chart-library="easypiechart"'
                + ' data-title="IPv4 Inbound"'
-               + ' data-units="kbps"'
                + ' data-width="10%"'
                + ' data-before="0"'
                + ' data-after="-' + duration.toString() + '"'
@@ -1870,7 +2137,6 @@ function headMain(charts, duration) {
                + ' data-dimensions="sent"'
                + ' data-chart-library="easypiechart"'
                + ' data-title="IPv4 Outbound"'
-               + ' data-units="kbps"'
                + ' data-width="10%"'
                + ' data-before="0"'
                + ' data-after="-' + duration.toString() + '"'
@@ -1953,7 +2219,7 @@ function renderPage(menus, data) {
                // generate an entry at the main menu
 
                var menuid = name2id(menu);
-               sidebar += '<li class=""><a href="#' + menuid + '">' + menus[menu].title + '</a><ul class="nav">';
+               sidebar += '<li class=""><a href="#' + menuid + '" onClick="return scrollToId(\'' + menuid + '\');">' + menus[menu].title + '</a><ul class="nav">';
                html += '<div role="section"><div role="sectionhead"><h1 id="' + menuid + '" role="heading">' + menus[menu].title + '</h1></div><div id="menu_' + menuid + '" role="document">';
 
                if(menus[menu].info !== null)
@@ -1973,7 +2239,7 @@ function renderPage(menus, data) {
 
                        // generate an entry at the submenu
                        var submenuid = name2id(menu + '_' + submenu);
-                       sidebar += '<li class><a href="#' + submenuid + '">' + menus[menu].submenus[submenu].title + '</a></li>';
+                       sidebar += '<li class><a href="#' + submenuid + '" onClick="return scrollToId(\'' + submenuid + '\');">' + menus[menu].submenus[submenu].title + '</a></li>';
                        shtml += '<div class="netdata-group-container" id="submenu_' + submenuid + '" style="display: inline-block; width: ' + pcent_width.toString() + '%"><h2 id="' + submenuid + '" class="netdata-chart-alignment" role="heading">' + menus[menu].submenus[submenu].title + '</h2>';
 
                        if(menus[menu].submenus[submenu].info !== null)
@@ -2083,6 +2349,8 @@ function downloadAllCharts(netdata_url) {
                netdata_url = NETDATA.serverDefault;
 
        NETDATA.pause(function() {
+               $("#loadOverlay").css("display","none");
+               $("#loadOverlay").css("display","none");
 
                // download all the charts the server knows
                NETDATA.chartRegistry.downloadAll(netdata_url, function(data) {
@@ -2091,7 +2359,7 @@ function downloadAllCharts(netdata_url) {
                        options.hostname = data.hostname;
                        document.getElementById('hostname').innerHTML = options.hostname;
                        document.getElementById('hostname').href = NETDATA.serverDefault;
-                       document.title = options.hostname + ' dashboard';
+                       document.title = options.hostname + ' netdata dashboard';
 
                        renderChartsAndMenu(data);
 
@@ -2226,21 +2494,6 @@ function notifyForUpdate(force) {
 
 // ----------------------------------------------------------------------------
 
-function getUrlParameter(sParam) {
-    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
-        sURLVariables = sPageURL.split('&'),
-        sParameterName,
-        i;
-
-    for (i = 0; i < sURLVariables.length; i++) {
-        sParameterName = sURLVariables[i].split('=');
-
-        if (sParameterName[0] === sParam) {
-            return sParameterName[1] === undefined ? true : sParameterName[1];
-        }
-    }
-}
-
 function finalizePage() {
        // resize all charts - without starting the background thread
        // this has to be done while NETDATA is paused
@@ -2248,14 +2501,9 @@ function finalizePage() {
        // the Dom elements are initially zero-sized
        NETDATA.parseDom();
 
-       var before = 0, after = 0, nowelcome = 0;
-       after = getUrlParameter('force_after_ms');
-       before = getUrlParameter('force_before_ms');
-       nowelcome = (getUrlParameter('nowelcome') === true)?true:false;
-
-       if(before > 0 && after > 0) {
-               nowelcome = true;
-               NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], after, before);
+       if(urlOptions.pan_and_zoom === true) {
+               urlOptions.nowelcome = true;
+               NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
        }
 
        // ------------------------------------------------------------------------
@@ -2393,18 +2641,14 @@ function finalizePage() {
        $(".chart-message").shorten();
        // ------------------------------------------------------------------------
 
+       // callback for us to track PanAndZoom operations
+       NETDATA.globalPanAndZoom.callback = netdataPanAndZoomCallback;
+
        // let it run (update the charts)
        NETDATA.unpause();
 
        // check if we have to jump to a specific section
-       var hash = location.hash.replace('#','');
-       if(hash != '') {
-               // Clear the hash in the URL
-               // location.hash = '';   // delete front "//" if you want to change the address bar
-               var offset = $(location.hash).offset();
-               if(typeof offset !== 'undefined')
-                       $('html, body').animate({ scrollTop: offset.top }, 0);
-       }
+       scrollToId(urlOptions.hash.replace('#',''));
 
        /* activate bootstrap sidebar (affix) */
        $('#sidebar').affix({
@@ -2427,19 +2671,21 @@ function finalizePage() {
                offset: $(window).height() / 3 // controls the diff of the <hX> element to the top, to select it
        });
 
-       $('#sidebar').on('activate.bs.scrollspy', function (e)
-       {
+       // change the URL based on the current position of the screen
+       $('#sidebar').on('activate.bs.scrollspy', function (e) {
                var el = $(e.target);
-               if (el.find('ul').size() == 0)
-               {
-                       var href = el.find('a').attr('href');
-                       history.pushState(null, document.title, href);
-               };
+               if(el.find('ul').size() == 0) {
+                       var hash = el.find('a').attr('href');
+                       if(typeof hash === 'string' && hash.substring(0, 1) == '#') {
+                               urlOptions.hash = hash;
+                               // console.log(urlOptions.hash);
+                               netdataHashUpdate();
+                       }
+               }
        });
 
        document.getElementById('footer').style.display = 'block';
 
-
        var update_options_modal = function() {
                // console.log('update_options_modal');
 
@@ -2489,13 +2735,18 @@ function finalizePage() {
        $('#stop_updates_when_focus_is_lost').change(function() { NETDATA.setOption('stop_updates_when_focus_is_lost', $(this).prop('checked')); });
        $('#smooth_plot').change(function()                     { NETDATA.setOption('smooth_plot', $(this).prop('checked')); });
        $('#pan_and_zoom_data_padding').change(function()       { NETDATA.setOption('pan_and_zoom_data_padding', $(this).prop('checked')); });
-       $('#show_help').change(function()                       { NETDATA.setOption('show_help', $(this).prop('checked')); location.reload(); });
+       $('#show_help').change(function()                       {
+               urlOptions.help = $(this).prop('checked');
+               NETDATA.setOption('show_help', urlOptions.help);
+               netdataReload();
+       });
 
        // this has to be the last
        // it reloads the page
        $('#netdata_theme_control').change(function() {
-               if(setTheme($(this).prop('checked')?'slate':'white'))
-                       location.reload();
+               urlOptions.theme = $(this).prop('checked')?'slate':'white';
+               if(setTheme(urlOptions.theme))
+                       netdataReload();
        });
 
        $('#updateModal').on('shown.bs.modal', function() {
@@ -2507,7 +2758,7 @@ function finalizePage() {
        });
 
        if(isdemo()) {
-               if(!nowelcome) {
+               if(!urlOptions.nowelcome) {
                        setTimeout(function() {
                                $('#welcomeModal').modal();
                        }, 1000);
@@ -2533,10 +2784,10 @@ function resetDashboardOptions() {
 
        NETDATA.resetOptions();
        if(setTheme('slate'))
-               location.reload();
+               netdataReload();
 
        if(help !== NETDATA.options.current.show_help)
-               location.reload();
+               netdataReload();
 }
 
 downloadAllCharts();