]> arthur.barton.de Git - netdata.git/blobdiff - web/index.html
increased version in html for CDN refresh; updated API reference for badge.svg; insta...
[netdata.git] / web / index.html
index 3dcef9087bde078cd2fe66f701731b3328897a7b..cb92af5ab791d3d5148674dc8b6ebda74d9113bc 100644 (file)
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html>
 <html lang="en">
 <head>
        <title>netdata dashboard</title>
        <link rel="icon" type="image/png" sizes="16x16" href="images/seo-performance-16.png">
 
        <meta property="og:locale" content="en_US" />
-       <meta property="og:image" content="https://my-netdata.io/images/seo-performance-512.png"/>
+       <meta property="og:image" content="http://my-netdata.io/images/post.png"/>
        <meta property="og:url" content="http://my-netdata.io/"/>
        <meta property="og:type" content="website"/>
        <meta property="og:site_name" content="netdata"/>
        <meta property="og:title" content="netdata - real-time performance monitoring, done right!"/>
-       <meta property="og:description" content="netdata is an embeddable real-time performance monitoring solution, for Linux systems, micro services, applications, APIs, SNMP devices. Stunning dashboards, blazzingly fast and extremely interactive." />
+       <meta property="og:description" content="Stunning real-time dashboards, blazingly fast and extremely interactive. Zero configuration, zero dependencies, zero maintenance." />
 
        <style>
 
                        return saveLocalStorage('netdataTheme', theme);
                }
 
-               var netdataRegistryCallback = function(urls_array) {
+               var netdataRegistryCallback = function(machines_array) {
                        var el = '';
                        var a1 = '';
                        var found = 0;
 
-                       if(urls_array) {
+                       if(machines_array) {
                                function name_comparator_desc(a, b) {
                                        if (a.name > b.name) return -1;
                                        if (a.name < b.name) return 1;
                                        return 0;
                                }
 
-                               var urls = urls_array.sort(name_comparator_desc);
-                               var len = urls.length;
+                               var machines = machines_array.sort(name_comparator_desc);
+                               var len = machines.length;
                                while(len--) {
-                                       var u = urls[len];
-
-                                       var status = "enabled";
+                                       var u = machines[len];
                                        found++;
-
-                                       if(u.guid === NETDATA.registry.machine_guid)
-                                               status = "disabled"
-
-                                       el += '<li id="registry_server_' + u.guid + '" class="' + status + '"><a href="' + u.url + '">' + u.name + '</a></li>';
+                                       el += '<li id="registry_server_' + u.guid + '"><a href="#" 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>';
                                }
                        }
 
                        if(!found) {
-                               if(urls)
+                               if(machines)
                                        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>';
                                else
                                        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>';
 
-                               a1 += '<li><a href="#">&nbsp;</a></li>';
+                               a1 += '<li><a href="#" onClick="return false;">&nbsp;</a></li>';
 
                                el += '<li role="separator" class="divider"></li>' +
                                                '<li><a href="//london.netdata.rocks/default.html">EU - London (DigitalOcean.com)</a></li>' +
        </script>
 
        <!-- load the dashboard manager - it will do the rest -->
-       <script type="text/javascript" src="dashboard.js?v37"></script>
+       <script type="text/javascript" src="dashboard.js?v39"></script>
 </head>
 
 <body data-spy="scroll" data-target="#sidebar">
                                                        <div class="row">
                                                                <div class="col-sm-6" style="width: 85%; padding-right: 0;">
                                                                        <ul id="mynetdata_servers" class="multi-column-dropdown">
-                                                                               <li><a href="#" onclck="return false;" style="color: #999;">loading...</a></li>
+                                                                               <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
                                                                        </ul>
                                                                </div>
                                                                <div class="col-sm-3 hidden-xs" style="width: 15%; padding-left: 0;">
                                        <li class="dropdown hidden-sm hidden-md hidden-lg">
                                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="current_view">my-netdata <strong class="caret"></strong></a>
                                                <ul id="mynetdata_servers2" class="dropdown-menu scrollable-menu inpagemenu" role="menu">
-                                                       <li><a href="#" onclck="return false;" style="color: #999;">loading...</a></li>
+                                                       <li><a href="#" onclick="return false;" style="color: #999;">loading...</a></li>
                                                </ul>
                                        </li>
                                </ul>
                                        <div id="versionCheckLog">Not checked yet. Please press the Check Now button.</div>
                                </div>
                                <div class="modal-footer">
-                                       <a href="#" onclick="notifyForUpdate(true);" type="button" class="btn btn-default">Check Now</a>
+                                       <a href="#" onclick="notifyForUpdate(true); return false;" type="button" class="btn btn-default">Check Now</a>
                                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                                </div>
                        </div>
                </div>
        </div>
 
+       <div class="modal fade" id="gotoServerModal" tabindex="-1" role="dialog" aria-labelledby="gotoServerModalLabel">
+               <div class="modal-dialog" role="document">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                                       <h4 class="modal-title" id="gotoServerModalLabel"><span id="gotoServerName"></span></h4>
+                               </div>
+                               <div class="modal-body">
+                                       Checking known URLs for this server...
+                                       <div  style="padding-top: 20px;">
+                                               <table id="gotoServerList">
+                                               </table>
+                                       </div>
+                                       <p style="padding-top: 10px;"><small>
+                                               Checks may fail if you are viewing an HTTPS page and the server to be checked is HTTP only.
+                                       </small></p>
+                                       <div id="gotoServerResponse" style="display: block; width: 100%; text-align: center; padding-top: 20px;"></div>
+                               </div>
+                               <div class="modal-footer">
+                                       <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                               </div>
+                       </div>
+               </div>
+       </div>
+
 <script>
 var this_is_demo = null;
 function isdemo() {
@@ -999,6 +1018,48 @@ function isdemo() {
 if(isdemo()) {
        document.getElementById('masthead').style.display = 'block';
 }
+var gotoServerValidateRemaining = 0;
+function gotoServerValidateUrl(id, guid, url) {
+       var penaldy = 0;
+       if(document.location.toString().startsWith('http://') && url.toString().startsWith('https://'))
+                       // we penalize https only if the current url is http
+                       // to allow the user walk through all its servers.
+                       penaldy = 500;
+
+       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>';
+               NETDATA.registry.hello(url, function(data) {
+                       if (data) {
+                               console.log('OK ' + id + ' URL: ' + url);
+                               document.getElementById(guid + '-' + id + '-status').innerHTML = "OK";
+                               document.location = url;
+                       }
+                       else {
+                               document.getElementById(guid + '-' + id + '-status').innerHTML = "failed!";
+                               gotoServerValidateRemaining--;
+                               if(gotoServerValidateRemaining <= 0)
+                                       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);
+
+       var len = NETDATA.registry.machines[guid].alternate_urls.length;
+
+       document.getElementById('gotoServerResponse').innerHTML = '';
+       document.getElementById('gotoServerList').innerHTML = '';
+       document.getElementById('gotoServerName').innerHTML = NETDATA.registry.machines[guid].name;
+       $('#gotoServerModal').modal('show');
+
+       gotoServerValidateRemaining = len;
+       while(len--)
+               gotoServerValidateUrl(len, guid, NETDATA.registry.machines[guid].alternate_urls[len]);
+
+       return false;
+}
 
 function switchRegistryModalHandler() {
        document.getElementById('switchRegistryPersonGUID').value = NETDATA.registry.person_guid;
@@ -1280,6 +1341,46 @@ var submenuData = {
 };
 
 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.'
        },
@@ -2157,6 +2258,141 @@ function finalizePage() {
                NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], after, before);
        }
 
+       // ------------------------------------------------------------------------
+       // https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
+       $.fn.shorten = function(settings) {
+               "use strict";
+
+               var config = {
+                       showChars: 750,
+                       minHideChars: 10,
+                       ellipsesText: "...",
+                       moreText: '<i class="fa fa-expand" aria-hidden="true"></i> show more information',
+                       lessText: '<i class="fa fa-compress" aria-hidden="true"></i> show less information',
+                       onLess: function() { NETDATA.onscroll(); },
+                       onMore: function() { NETDATA.onscroll(); },
+                       errMsg: null,
+                       force: false
+               };
+
+               if (settings) {
+                       $.extend(config, settings);
+               }
+
+               if ($(this).data('jquery.shorten') && !config.force) {
+                       return false;
+               }
+               $(this).data('jquery.shorten', true);
+
+               $(document).off("click", '.morelink');
+
+               $(document).on({
+                       click: function() {
+
+                               var $this = $(this);
+                               if ($this.hasClass('less')) {
+                                       $this.removeClass('less');
+                                       $this.html(config.moreText);
+                                       $this.parent().prev().animate({'height':'0'+'%'}, 0, function () { $this.parent().prev().prev().show(); }).hide(0, function() {
+                                               config.onLess();
+                                       });
+
+                               } else {
+                                       $this.addClass('less');
+                                       $this.html(config.lessText);
+                                       $this.parent().prev().animate({'height':'100'+'%'}, 0, function () { $this.parent().prev().prev().hide(); }).show(0, function() {
+                                               config.onMore();
+                                       });
+                               }
+                               return false;
+                       }
+               }, '.morelink');
+
+               return this.each(function() {
+                       var $this = $(this);
+
+                       var content = $this.html();
+                       var contentlen = $this.text().length;
+                       if (contentlen > config.showChars + config.minHideChars) {
+                               var c = content.substr(0, config.showChars);
+                               if (c.indexOf('<') >= 0) // If there's HTML don't want to cut it
+                               {
+                                       var inTag = false; // I'm in a tag?
+                                       var bag = ''; // Put the characters to be shown here
+                                       var countChars = 0; // Current bag size
+                                       var openTags = []; // Stack for opened tags, so I can close them later
+                                       var tagName = null;
+
+                                       for (var i = 0, r = 0; r <= config.showChars; i++) {
+                                               if (content[i] == '<' && !inTag) {
+                                                       inTag = true;
+
+                                                       // This could be "tag" or "/tag"
+                                                       tagName = content.substring(i + 1, content.indexOf('>', i));
+
+                                                       // If its a closing tag
+                                                       if (tagName[0] == '/') {
+
+
+                                                               if (tagName != '/' + openTags[0]) {
+                                                                       config.errMsg = 'ERROR en HTML: the top of the stack should be the tag that closes';
+                                                               } else {
+                                                                       openTags.shift(); // Pops the last tag from the open tag stack (the tag is closed in the retult HTML!)
+                                                               }
+
+                                                       } else {
+                                                               // There are some nasty tags that don't have a close tag like <br/>
+                                                               if (tagName.toLowerCase() != 'br') {
+                                                                       openTags.unshift(tagName); // Add to start the name of the tag that opens
+                                                               }
+                                                       }
+                                               }
+                                               if (inTag && content[i] == '>') {
+                                                       inTag = false;
+                                               }
+
+                                               if (inTag) { bag += content.charAt(i); } // Add tag name chars to the result
+                                               else {
+                                                       r++;
+                                                       if (countChars <= config.showChars) {
+                                                               bag += content.charAt(i); // Fix to ie 7 not allowing you to reference string characters using the []
+                                                               countChars++;
+                                                       } else // Now I have the characters needed
+                                                       {
+                                                               if (openTags.length > 0) // I have unclosed tags
+                                                               {
+                                                                       //console.log('They were open tags');
+                                                                       //console.log(openTags);
+                                                                       for (j = 0; j < openTags.length; j++) {
+                                                                               //console.log('Cierro tag ' + openTags[j]);
+                                                                               bag += '</' + openTags[j] + '>'; // Close all tags that were opened
+
+                                                                               // 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
+                                                                       }
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       c = $('<div/>').html(bag + '<span class="ellip">' + config.ellipsesText + '</span>').html();
+                               }else{
+                                       c+=config.ellipsesText;
+                               }
+
+                               var html = '<div class="shortcontent">' + c +
+                                               '</div><div class="allcontent">' + content +
+                                               '</div><span><a href="javascript://nop/" class="morelink">' + config.moreText + '</a></span>';
+
+                               $this.html(html);
+                               $this.find(".allcontent").hide(); // Hide all text
+                               $('.shortcontent p:last', $this).css('margin-bottom', 0); //Remove bottom margin on last paragraph as it's likely shortened
+                       }
+               });
+
+       };
+       $(".chart-message").shorten();
+       // ------------------------------------------------------------------------
+
        // let it run (update the charts)
        NETDATA.unpause();
 
@@ -2191,6 +2427,16 @@ 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)
+       {
+               var el = $(e.target);
+               if (el.find('ul').size() == 0)
+               {
+                       var href = el.find('a').attr('href');
+                       history.pushState(null, document.title, href);
+               };
+       });
+
        document.getElementById('footer').style.display = 'block';