473 lines
18 KiB
JavaScript
473 lines
18 KiB
JavaScript
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
|
/**
|
|
* @fileoverview functions used in server status pages
|
|
* @name Server Status
|
|
*
|
|
* @requires jQuery
|
|
* @requires jQueryUI
|
|
* @requires jQueryCookie
|
|
* @requires jQueryTablesorter
|
|
* @requires Highcharts
|
|
* @requires canvg
|
|
* @requires js/functions.js
|
|
*
|
|
*/
|
|
|
|
// Add a tablesorter parser to properly handle thousands seperated numbers and SI prefixes
|
|
$(function() {
|
|
jQuery.tablesorter.addParser({
|
|
id: "fancyNumber",
|
|
is: function(s) {
|
|
return /^[0-9]?[0-9,\.]*\s?(k|M|G|T|%)?$/.test(s);
|
|
},
|
|
format: function(s) {
|
|
var num = jQuery.tablesorter.formatFloat(
|
|
s.replace(PMA_messages['strThousandsSeperator'],'')
|
|
.replace(PMA_messages['strDecimalSeperator'],'.')
|
|
);
|
|
|
|
var factor = 1;
|
|
switch (s.charAt(s.length - 1)) {
|
|
case '%': factor = -2; break;
|
|
// Todo: Complete this list (as well as in the regexp a few lines up)
|
|
case 'k': factor = 3; break;
|
|
case 'M': factor = 6; break;
|
|
case 'G': factor = 9; break;
|
|
case 'T': factor = 12; break;
|
|
}
|
|
|
|
return num * Math.pow(10,factor);
|
|
},
|
|
type: "numeric"
|
|
});
|
|
});
|
|
|
|
$(function() {
|
|
// Filters for status variables
|
|
var textFilter=null;
|
|
var alertFilter = false;
|
|
var categoryFilter='';
|
|
var odd_row=false;
|
|
var text=''; // Holds filter text
|
|
var queryPieChart = null;
|
|
|
|
/* Chart configuration */
|
|
// Defines what the tabs are currently displaying (realtime or data)
|
|
var tabStatus = new Object();
|
|
// Holds the current chart instances for each tab
|
|
var tabChart = new Object();
|
|
|
|
$.ajaxSetup({
|
|
cache:false
|
|
});
|
|
|
|
// Add tabs
|
|
$('#serverStatusTabs').tabs({
|
|
// Tab persistence
|
|
cookie: { name: 'pma_serverStatusTabs', expires: 1 },
|
|
// Fixes line break in the menu bar when the page overflows and scrollbar appears
|
|
show: function() { menuResize(); }
|
|
});
|
|
|
|
// Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601
|
|
$(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix");
|
|
|
|
// Initialize each tab
|
|
$('div.ui-tabs-panel').each(function() {
|
|
initTab($(this),null);
|
|
tabStatus[$(this).attr('id')] = 'static';
|
|
});
|
|
|
|
// Handles refresh rate changing
|
|
$('.statuslinks select').change(function() {
|
|
var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')];
|
|
chart.options.realtime.refreshRate = 1000*parseInt(this.value);
|
|
|
|
chart.xAxis[0].setExtremes(
|
|
new Date().getTime() - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate,
|
|
chart.xAxis[0].getExtremes().max,
|
|
true
|
|
);
|
|
|
|
// Clear current timeout and set timeout with the new refresh rate
|
|
clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]);
|
|
chart_activeTimeouts[chart.options.chart.renderTo] = setTimeout(
|
|
chart.options.realtime.timeoutCallBack,
|
|
chart.options.realtime.refreshRate
|
|
);
|
|
});
|
|
|
|
// Ajax refresh of variables (always the first element in each tab)
|
|
$('.statuslinks a.tabRefresh').click(function() {
|
|
// ui-tabs-panel class is added by the jquery tabs feature
|
|
var tab=$(this).parents('div.ui-tabs-panel');
|
|
var that = this;
|
|
|
|
// Show ajax load icon
|
|
$(this).find('img').show();
|
|
|
|
$.get($(this).attr('href'),{ajax_request:1},function(data) {
|
|
$(that).find('img').hide();
|
|
initTab(tab,data);
|
|
});
|
|
|
|
tabStatus[tab.attr('id')]='data';
|
|
|
|
return false;
|
|
});
|
|
|
|
|
|
/** Realtime charting of variables **/
|
|
|
|
// Live traffic charting
|
|
$('.statuslinks a.livetrafficLink').click(function() {
|
|
// ui-tabs-panel class is added by the jquery tabs feature
|
|
var $tab=$(this).parents('div.ui-tabs-panel');
|
|
var tabstat = tabStatus[$tab.attr('id')];
|
|
|
|
if(tabstat=='static' || tabstat=='liveconnections') {
|
|
var settings = {
|
|
series: [
|
|
{ name: PMA_messages['strChartKBSent'], data: [] },
|
|
{ name: PMA_messages['strChartKBReceived'], data: [] }
|
|
],
|
|
title: { text: PMA_messages['strChartServerTraffic'] },
|
|
realtime: { url:'server_status.php?' + url_query,
|
|
type: 'traffic',
|
|
callback: function(chartObj, curVal, lastVal, numLoadedPoints) {
|
|
if(lastVal==null) return;
|
|
chartObj.series[0].addPoint(
|
|
{ x: curVal.x, y: (curVal.y_sent - lastVal.y_sent) / 1024 },
|
|
false,
|
|
numLoadedPoints >= chartObj.options.realtime.numMaxPoints
|
|
);
|
|
chartObj.series[1].addPoint(
|
|
{ x: curVal.x, y: (curVal.y_received - lastVal.y_received) / 1024 },
|
|
true,
|
|
numLoadedPoints >= chartObj.options.realtime.numMaxPoints
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
setupLiveChart($tab,this,settings);
|
|
if(tabstat == 'liveconnections')
|
|
$tab.find('.statuslinks a.liveconnectionsLink').html(PMA_messages['strLiveConnChart']);
|
|
tabStatus[$tab.attr('id')]='livetraffic';
|
|
} else {
|
|
$(this).html(PMA_messages['strLiveTrafficChart']);
|
|
setupLiveChart($tab,this,null);
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
// Live connection/process charting
|
|
$('.statuslinks a.liveconnectionsLink').click(function() {
|
|
var $tab=$(this).parents('div.ui-tabs-panel');
|
|
var tabstat = tabStatus[$tab.attr('id')];
|
|
|
|
if(tabstat == 'static' || tabstat == 'livetraffic') {
|
|
var settings = {
|
|
series: [
|
|
{ name: PMA_messages['strChartConnections'], data: [] },
|
|
{ name: PMA_messages['strChartProcesses'], data: [] }
|
|
],
|
|
title: { text: PMA_messages['strChartConnectionsTitle'] },
|
|
realtime: { url:'server_status.php?'+url_query,
|
|
type: 'proc',
|
|
callback: function(chartObj, curVal, lastVal,numLoadedPoints) {
|
|
if(lastVal==null) return;
|
|
chartObj.series[0].addPoint(
|
|
{ x: curVal.x, y: curVal.y_conn - lastVal.y_conn },
|
|
false,
|
|
numLoadedPoints >= chartObj.options.realtime.numMaxPoints
|
|
);
|
|
chartObj.series[1].addPoint(
|
|
{ x: curVal.x, y: curVal.y_proc },
|
|
true,
|
|
numLoadedPoints >= chartObj.options.realtime.numMaxPoints
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
setupLiveChart($tab,this,settings);
|
|
if(tabstat == 'livetraffic')
|
|
$tab.find('.statuslinks a.livetrafficLink').html(PMA_messages['strLiveTrafficChart']);
|
|
tabStatus[$tab.attr('id')]='liveconnections';
|
|
} else {
|
|
$(this).html(PMA_messages['strLiveConnChart']);
|
|
setupLiveChart($tab,this,null);
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
// Live query statistics
|
|
$('.statuslinks a.livequeriesLink').click(function() {
|
|
var $tab = $(this).parents('div.ui-tabs-panel');
|
|
var settings = null;
|
|
|
|
if(tabStatus[$tab.attr('id')] == 'static') {
|
|
settings = {
|
|
series: [ { name: PMA_messages['strChartIssuedQueries'], data: [] } ],
|
|
title: { text: PMA_messages['strChartIssuedQueriesTitle'] },
|
|
tooltip: { formatter:function() { return this.point.name; } },
|
|
realtime: { url:'server_status.php?'+url_query,
|
|
type: 'queries',
|
|
callback: function(chartObj, curVal, lastVal,numLoadedPoints) {
|
|
if(lastVal == null) return;
|
|
chartObj.series[0].addPoint(
|
|
{ x: curVal.x, y: curVal.y - lastVal.y, name: sortedQueriesPointInfo(curVal,lastVal) },
|
|
true,
|
|
numLoadedPoints >= chartObj.options.realtime.numMaxPoints
|
|
);
|
|
}
|
|
}
|
|
};
|
|
} else {
|
|
$(this).html(PMA_messages['strLiveQueryChart']);
|
|
}
|
|
|
|
setupLiveChart($tab,this,settings);
|
|
tabStatus[$tab.attr('id')] = 'livequeries';
|
|
return false;
|
|
});
|
|
|
|
function setupLiveChart($tab,link,settings) {
|
|
if(settings != null) {
|
|
// Loading a chart with existing chart => remove old chart first
|
|
if(tabStatus[$tab.attr('id')] != 'static') {
|
|
clearTimeout(chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]);
|
|
chart_activeTimeouts[$tab.attr('id')+"_chart_cnt"] = null;
|
|
tabChart[$tab.attr('id')].destroy();
|
|
// Also reset the select list
|
|
$tab.find('.statuslinks select').get(0).selectedIndex = 0;
|
|
}
|
|
|
|
if(! settings.chart) settings.chart = {};
|
|
settings.chart.renderTo = $tab.attr('id') + "_chart_cnt";
|
|
|
|
$tab.find('.tabInnerContent')
|
|
.hide()
|
|
.after('<div class="liveChart" id="' + $tab.attr('id') + '_chart_cnt"></div>');
|
|
tabChart[$tab.attr('id')] = PMA_createChart(settings);
|
|
$(link).html(PMA_messages['strStaticData']);
|
|
$tab.find('.statuslinks a.tabRefresh').hide();
|
|
$tab.find('.statuslinks select').show();
|
|
} else {
|
|
clearTimeout(chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]);
|
|
chart_activeTimeouts[$tab.attr('id') + "_chart_cnt"]=null;
|
|
$tab.find('.tabInnerContent').show();
|
|
$tab.find('div#'+$tab.attr('id') + '_chart_cnt').remove();
|
|
tabStatus[$tab.attr('id')]='static';
|
|
tabChart[$tab.attr('id')].destroy();
|
|
$tab.find('.statuslinks a.tabRefresh').show();
|
|
$tab.find('.statuslinks select').get(0).selectedIndex=0;
|
|
$tab.find('.statuslinks select').hide();
|
|
}
|
|
}
|
|
|
|
/* 3 Filtering functions */
|
|
$('#filterAlert').change(function() {
|
|
alertFilter = this.checked;
|
|
filterVariables();
|
|
});
|
|
|
|
$('#filterText').keyup(function(e) {
|
|
if($(this).val().length == 0) textFilter = null;
|
|
else textFilter = new RegExp("(^|_)" + $(this).val(),'i');
|
|
|
|
text = $(this).val();
|
|
filterVariables();
|
|
});
|
|
|
|
$('#filterCategory').change(function() {
|
|
categoryFilter = $(this).val();
|
|
filterVariables();
|
|
});
|
|
|
|
/* Adjust DOM / Add handlers to the tabs */
|
|
function initTab(tab,data) {
|
|
switch(tab.attr('id')) {
|
|
case 'statustabs_traffic':
|
|
if(data != null) tab.find('.tabInnerContent').html(data);
|
|
initTooltips();
|
|
break;
|
|
case 'statustabs_queries':
|
|
if(data != null) {
|
|
queryPieChart.destroy();
|
|
tab.find('.tabInnerContent').html(data);
|
|
}
|
|
|
|
// Build query statistics chart
|
|
var cdata = new Array();
|
|
$.each(jQuery.parseJSON($('#serverstatusquerieschart').html()),function(key,value) {
|
|
cdata.push([key,parseInt(value)]);
|
|
});
|
|
|
|
queryPieChart = PMA_createChart({
|
|
chart: {
|
|
renderTo: 'serverstatusquerieschart'
|
|
},
|
|
title: {
|
|
text:'',
|
|
margin:0
|
|
},
|
|
series: [{
|
|
type:'pie',
|
|
name: PMA_messages['strChartQueryPie'],
|
|
data: cdata
|
|
}],
|
|
plotOptions: {
|
|
pie: {
|
|
allowPointSelect: true,
|
|
cursor: 'pointer',
|
|
dataLabels: {
|
|
enabled: true,
|
|
formatter: function() {
|
|
return '<b>'+ this.point.name +'</b><br/> ' + Highcharts.numberFormat(this.percentage, 2) + ' %';
|
|
}
|
|
}
|
|
}
|
|
},
|
|
tooltip: {
|
|
formatter: function() {
|
|
return '<b>' + this.point.name + '</b><br/>' + Highcharts.numberFormat(this.y, 2) + '<br/>(' + Highcharts.numberFormat(this.percentage, 2) + ' %)';
|
|
}
|
|
}
|
|
});
|
|
break;
|
|
|
|
case 'statustabs_allvars':
|
|
if(data != null) {
|
|
tab.find('.tabInnerContent').html(data);
|
|
filterVariables();
|
|
}
|
|
break;
|
|
}
|
|
|
|
initTableSorter(tab.attr('id'));
|
|
}
|
|
|
|
function initTableSorter(tabid) {
|
|
switch(tabid) {
|
|
case 'statustabs_queries':
|
|
$('#serverstatusqueriesdetails').tablesorter({
|
|
sortList: [[3,1]],
|
|
widgets: ['zebra'],
|
|
headers: {
|
|
1: { sorter: 'fancyNumber' },
|
|
2: { sorter: 'fancyNumber' }
|
|
}
|
|
});
|
|
|
|
$('#serverstatusqueriesdetails tr:first th')
|
|
.append('<img class="sortableIcon" src="' + pma_theme_image + 'cleardot.gif" alt="">');
|
|
|
|
break;
|
|
|
|
case 'statustabs_allvars':
|
|
$('#serverstatusvariables').tablesorter({
|
|
sortList: [[0,0]],
|
|
widgets: ['zebra'],
|
|
headers: {
|
|
1: { sorter: 'fancyNumber' }
|
|
}
|
|
});
|
|
|
|
$('#serverstatusvariables tr:first th')
|
|
.append('<img class="sortableIcon" src="' + pma_theme_image + 'cleardot.gif" alt="">');
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Filters the status variables by name/category/alert in the variables tab */
|
|
function filterVariables() {
|
|
var useful_links = 0;
|
|
var section = text;
|
|
|
|
if(categoryFilter.length > 0) section = categoryFilter;
|
|
|
|
if(section.length > 1) {
|
|
$('#linkSuggestions span').each(function() {
|
|
if($(this).attr('class').indexOf('status_'+section) != -1) {
|
|
useful_links++;
|
|
$(this).css('display','');
|
|
} else {
|
|
$(this).css('display','none');
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
if(useful_links > 0)
|
|
$('#linkSuggestions').css('display','');
|
|
else $('#linkSuggestions').css('display','none');
|
|
|
|
odd_row=false;
|
|
$('#serverstatusvariables th.name').each(function() {
|
|
if((textFilter == null || textFilter.exec($(this).text()))
|
|
&& (! alertFilter || $(this).next().find('span.attention').length>0)
|
|
&& (categoryFilter.length == 0 || $(this).parent().hasClass('s_'+categoryFilter))) {
|
|
odd_row = ! odd_row;
|
|
$(this).parent().css('display','');
|
|
if(odd_row) {
|
|
$(this).parent().addClass('odd');
|
|
$(this).parent().removeClass('even');
|
|
} else {
|
|
$(this).parent().addClass('even');
|
|
$(this).parent().removeClass('odd');
|
|
}
|
|
} else {
|
|
$(this).parent().css('display','none');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Provides a nicely formatted and sorted tooltip of each datapoint of the query statistics
|
|
function sortedQueriesPointInfo(queries, lastQueries){
|
|
var max, maxIdx, num=0;
|
|
var queryKeys = new Array();
|
|
var queryValues = new Array();
|
|
var sumOther=0;
|
|
var sumTotal=0;
|
|
|
|
// Separate keys and values, then sort them
|
|
$.each(queries.pointInfo, function(key,value) {
|
|
if(value-lastQueries.pointInfo[key] > 0) {
|
|
queryKeys.push(key);
|
|
queryValues.push(value-lastQueries.pointInfo[key]);
|
|
sumTotal += value-lastQueries.pointInfo[key];
|
|
}
|
|
});
|
|
var numQueries = queryKeys.length;
|
|
var pointInfo = '<b>' + PMA_messages['strTotal'] + ': ' + sumTotal + '</b><br>';
|
|
|
|
while(queryKeys.length > 0) {
|
|
max = 0;
|
|
for(var i=0; i < queryKeys.length; i++) {
|
|
if(queryValues[i] > max) {
|
|
max = queryValues[i];
|
|
maxIdx = i;
|
|
}
|
|
}
|
|
if(numQueries > 8 && num >= 6)
|
|
sumOther += queryValues[maxIdx];
|
|
else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '<br>';
|
|
|
|
queryKeys.splice(maxIdx,1);
|
|
queryValues.splice(maxIdx,1);
|
|
num++;
|
|
}
|
|
|
|
if(sumOther>0)
|
|
pointInfo += PMA_messages['strOther'] + ': ' + sumOther;
|
|
|
|
return pointInfo;
|
|
}
|
|
|
|
}); |