/* 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" }); // Popup behaviour $('a[rel="popupLink"]').click( function() { var $link = $(this); $('.' + $link.attr('href').substr(1)) .show() .offset({ top: $link.offset().top + $link.height() + 5, left: $link.offset().left }) .addClass('openedPopup'); return false; }); $(document).click( function(event) { $('.openedPopup').each(function() { var $cnt = $(this); var pos = $(this).offset(); // Hide if the mouseclick is outside the popupcontent if(event.pageX < pos.left || event.pageY < pos.top || event.pageX > pos.left + $cnt.outerWidth() || event.pageY > pos.top + $cnt.outerHeight()) $cnt.hide().removeClass('openedPopup'); }); }); }); $(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(); /*** Table sort tooltip ***/ var $tableSortHint = $('
'); $('body').append($tableSortHint); $('table.sortable thead th').live('mouseover mouseout',function(e) { if(e.type == 'mouseover') { $tableSortHint .stop(true, true) .css({ top: e.clientY + 15, left: e.clientX + 15 }) .show('fast') .data('shown',true); } else { $tableSortHint .stop(true, true) .hide(300,function() { $(this).data('shown',false); }); } }); $(document).mousemove(function(e) { if($tableSortHint.data('shown') == true) $tableSortHint.css({ top: e.clientY + 15, left: e.clientX + 15 }) }); // Tell highcarts not to use UTC dates (global setting) Highcharts.setOptions({ global: { useUTC: false } }); $.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'; }); // Display button links $('div.buttonlinks').show(); // Handles refresh rate changing $('.buttonlinks select').change(function() { var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')]; // Clear current timeout and set timeout with the new refresh rate clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]); if(chart.options.realtime.postRequest) chart.options.realtime.postRequest.abort(); chart.options.realtime.refreshRate = 1000*parseInt(this.value); chart.xAxis[0].setExtremes( new Date().getTime() - server_time_diff - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate, new Date().getTime() - server_time_diff, true ); 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) $('.buttonlinks 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 $('.buttonlinks 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('.buttonlinks 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 $('.buttonlinks 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('.buttonlinks 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 $('.buttonlinks 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('.buttonlinks select').get(0).selectedIndex = 2; } if(! settings.chart) settings.chart = {}; settings.chart.renderTo = $tab.attr('id') + "_chart_cnt"; $tab.find('.tabInnerContent') .hide() .after(''); tabChart[$tab.attr('id')] = PMA_createChart(settings); $(link).html(PMA_messages['strStaticData']); $tab.find('.buttonlinks a.tabRefresh').hide(); $tab.find('.buttonlinks .refreshList').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('.buttonlinks a.tabRefresh').show(); $tab.find('.buttonlinks select').get(0).selectedIndex=2; $tab.find('.buttonlinks .refreshList').hide(); } } /* 3 Filtering functions */ $('#filterAlert').change(function() { alertFilter = this.checked; filterVariables(); }); $('#filterText').keyup(function(e) { word = $(this).val().replace('_',' '); if(word.length == 0) textFilter = null; else textFilter = new RegExp("(^|_)" + word,'i'); text = word; 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 span').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 ''+ this.point.name +'
');
break;
case 'statustabs_allvars':
$('#serverstatusvariables').tablesorter({
sortList: [[0,0]],
widgets: ['zebra'],
headers: {
1: { sorter: 'fancyNumber' }
}
});
$('#serverstatusvariables tr:first th')
.append('
');
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 = '' + PMA_messages['strTotal'] + ': ' + sumTotal + '
' + PMA_messages['strResumeMonitor']);
else {
$(this).html('
' + PMA_messages['strPauseMonitor']);
if(runtime.charts == null) {
initGrid();
$('a[href="#settingsPopup"]').show();
}
}
return false;
});
$('a[href="#monitorInstructionsDialog"]').click(function() {
var $dialog = $('div#monitorInstructionsDialog');
$dialog.dialog({
width: 595,
height: 'auto'
}).find('img.ajaxIcon').show();
var loadLogVars = function(getvars) {
vars = { ajax_request: true, logging_vars: true };
if(getvars) $.extend(vars,getvars);
$.get('server_status.php?' + url_query, vars,
function(data) {
var logVars = $.parseJSON(data),
icon = 's_success.png', msg='', str='';
if(logVars['general_log'] == 'ON') {
if(logVars['slow_query_log'] == 'ON')
msg = PMA_messages['strBothLogOn'];
else
msg = PMA_messages['strGenLogOn'];
}
if(msg.length == 0 && logVars['slow_query_log'] == 'ON') {
msg = PMA_messages['strSlowLogOn'];
}
if(msg.length == 0) {
icon = 's_error.png';
msg = PMA_messages['strBothLogOff'];
}
str = '' + PMA_messages['strCurrentSettings'] + '
' + PMA_messages['strLogOutNotTable'] + '
' + PMA_messages['strLogOutIsTable'] + '
'
+ $.sprintf(PMA_messages['strSmallerLongQueryTimeAdvice'], logVars['long_query_time'])
+ '
'
+ $.sprintf(PMA_messages['strLongQueryTimeSet'], logVars['long_query_time'])
+ '
');
$('#loadingLogsDialog').dialog({
width: 'auto',
height: 'auto',
buttons: {
'Cancel request': function() {
if(logRequest != null)
logRequest.abort();
$(this).dialog("close");
}
}
});
var formatValue = function(name, value) {
switch(name) {
case 'user_host':
return value.replace(/(\[.*?\])+/g,'');
}
return value;
}
logRequest = $.get('server_status.php?'+url_query,
{ ajax_request: true, log_data: 1, type: opts.src, time_start: Math.round(opts.start / 1000), time_end: Math.round(opts.end / 1000), groupInserts: groupInserts },
function(data) {
var data = $.parseJSON(data);
var rows = data.rows;
var cols = new Array();
if(rows.length != 0) {
tableStr = '| ' + cols.join(' | ') + ' |
|---|---|
| ' + formatValue(cols[j], rows[i][cols[j]]) + ' | '; tableStr += '
');
var qtipContent = PMA_messages['strCountColumnExplanation'];
if(groupInserts) qtipContent += '' + PMA_messages['strMoreCountColumnExplanation'] + '
'; $('img.qroupedQueryInfoIcon').qtip({ content: qtipContent, position: { corner: { target: 'bottomMiddle', tooltip: 'topRight' } }, hide: { delay: 1000 } }) } $('div#logTable table').tablesorter({ sortList: [[0,1]], widgets: ['zebra'] }); $('div#logTable table thead th') .append('
');
$('#loadingLogsDialog').html('' + PMA_messages['strLogDataLoaded'] + '
'); $.each(data.sum, function(key, value) { key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase(); if(key == 'Total') key = '' + key + ''; $('#loadingLogsDialog').append(key + ': ' + value + '' + PMA_messages['strNoDataFound'] + '
'); var dlgBtns = {}; dlgBtns[PMA_messages['strClose']] = function() { $(this).dialog("close"); } $('#loadingLogsDialog').dialog( "option", "buttons", dlgBtns ); } } ); } function saveMonitor() { var gridCopy = {}; $.each(runtime.charts, function(key, elem) { gridCopy[key] = {}; gridCopy[key].nodes = elem.nodes; gridCopy[key].settings = elem.settings; gridCopy[key].title = elem.title; }); if(window.localStorage) { window.localStorage['monitorCharts'] = $.toJSON(gridCopy); window.localStorage['monitorSettings'] = $.toJSON(monitorSettings); } $('a[href="#clearMonitorConfig"]').show(); } $('a[href="#clearMonitorConfig"]').click(function() { window.localStorage.removeItem('monitorCharts'); window.localStorage.removeItem('monitorSettings'); $(this).hide(); }); });