Merge remote-tracking branch 'origin/QA_4_0'
[phpmyadmin/aamir.git] / server_status_monitor.php
blobce093bdd5a7f2d78cf7042b4773bf3039c9f2d23
1 <?php
2 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 /**
4 * Server status monitor feature
6 * @package PhpMyAdmin
7 */
9 require_once 'libraries/common.inc.php';
10 require_once 'libraries/server_common.inc.php';
11 require_once 'libraries/ServerStatusData.class.php';
12 require_once 'libraries/server_status_monitor.lib.php';
13 if (PMA_DRIZZLE) {
14 $server_master_status = false;
15 $server_slave_status = false;
16 } else {
17 include_once 'libraries/replication.inc.php';
18 include_once 'libraries/replication_gui.lib.php';
21 /**
22 * Ajax request
24 if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
25 // Send with correct charset
26 header('Content-Type: text/html; charset=UTF-8');
28 // real-time charting data
29 if (isset($_REQUEST['chart_data'])) {
30 switch($_REQUEST['type']) {
31 case 'chartgrid': // Data for the monitor
32 $ret = json_decode($_REQUEST['requiredData'], true);
33 $statusVars = array();
34 $serverVars = array();
35 $sysinfo = $cpuload = $memory = 0;
36 $pName = '';
38 /* Accumulate all required variables and data */
39 // For each chart
40 foreach ($ret as $chart_id => $chartNodes) {
41 // For each data series
42 foreach ($chartNodes as $node_id => $nodeDataPoints) {
43 // For each data point in the series (usually just 1)
44 foreach ($nodeDataPoints as $point_id => $dataPoint) {
45 $pName = $dataPoint['name'];
47 switch ($dataPoint['type']) {
48 /* We only collect the status and server variables here to
49 * read them all in one query,
50 * and only afterwards assign them.
51 * Also do some white list filtering on the names
53 case 'servervar':
54 if (! preg_match('/[^a-zA-Z_]+/', $pName)) {
55 $serverVars[] = $pName;
57 break;
59 case 'statusvar':
60 if (! preg_match('/[^a-zA-Z_]+/', $pName)) {
61 $statusVars[] = $pName;
63 break;
65 case 'proc':
66 $result = $GLOBALS['dbi']->query('SHOW PROCESSLIST');
67 $ret[$chart_id][$node_id][$point_id]['value']
68 = $GLOBALS['dbi']->numRows($result);
69 break;
71 case 'cpu':
72 if (!$sysinfo) {
73 include_once 'libraries/sysinfo.lib.php';
74 $sysinfo = PMA_getSysInfo();
76 if (!$cpuload) {
77 $cpuload = $sysinfo->loadavg();
80 if (PMA_getSysInfoOs() == 'Linux') {
81 $ret[$chart_id][$node_id][$point_id]['idle']
82 = $cpuload['idle'];
83 $ret[$chart_id][$node_id][$point_id]['busy']
84 = $cpuload['busy'];
85 } else {
86 $ret[$chart_id][$node_id][$point_id]['value']
87 = $cpuload['loadavg'];
90 break;
92 case 'memory':
93 if (!$sysinfo) {
94 include_once 'libraries/sysinfo.lib.php';
95 $sysinfo = PMA_getSysInfo();
97 if (!$memory) {
98 $memory = $sysinfo->memory();
101 $ret[$chart_id][$node_id][$point_id]['value']
102 = $memory[$pName];
103 break;
104 } /* switch */
105 } /* foreach */
106 } /* foreach */
107 } /* foreach */
109 // Retrieve all required status variables
110 if (count($statusVars)) {
111 $statusVarValues = $GLOBALS['dbi']->fetchResult(
112 "SHOW GLOBAL STATUS WHERE Variable_name='"
113 . implode("' OR Variable_name='", $statusVars) . "'",
117 } else {
118 $statusVarValues = array();
121 // Retrieve all required server variables
122 if (count($serverVars)) {
123 $serverVarValues = $GLOBALS['dbi']->fetchResult(
124 "SHOW GLOBAL VARIABLES WHERE Variable_name='"
125 . implode("' OR Variable_name='", $serverVars) . "'",
129 } else {
130 $serverVarValues = array();
133 // ...and now assign them
134 foreach ($ret as $chart_id => $chartNodes) {
135 foreach ($chartNodes as $node_id => $nodeDataPoints) {
136 foreach ($nodeDataPoints as $point_id => $dataPoint) {
137 switch($dataPoint['type']) {
138 case 'statusvar':
139 $ret[$chart_id][$node_id][$point_id]['value']
140 = $statusVarValues[$dataPoint['name']];
141 break;
142 case 'servervar':
143 $ret[$chart_id][$node_id][$point_id]['value']
144 = $serverVarValues[$dataPoint['name']];
145 break;
151 $ret['x'] = microtime(true) * 1000;
153 PMA_Response::getInstance()->addJSON('message', $ret);
154 exit;
158 if (isset($_REQUEST['log_data'])) {
159 if (PMA_MYSQL_INT_VERSION < 50106) {
160 // Table logging is only available since 5.1.6
161 exit('""');
164 $start = intval($_REQUEST['time_start']);
165 $end = intval($_REQUEST['time_end']);
167 if ($_REQUEST['type'] == 'slow') {
168 $q = 'SELECT start_time, user_host, ';
169 $q .= 'Sec_to_Time(Sum(Time_to_Sec(query_time))) as query_time, ';
170 $q .= 'Sec_to_Time(Sum(Time_to_Sec(lock_time))) as lock_time, ';
171 $q .= 'SUM(rows_sent) AS rows_sent, ';
172 $q .= 'SUM(rows_examined) AS rows_examined, db, sql_text, ';
173 $q .= 'COUNT(sql_text) AS \'#\' ';
174 $q .= 'FROM `mysql`.`slow_log` ';
175 $q .= 'WHERE start_time > FROM_UNIXTIME(' . $start . ') ';
176 $q .= 'AND start_time < FROM_UNIXTIME(' . $end . ') GROUP BY sql_text';
178 $result = $GLOBALS['dbi']->tryQuery($q);
180 $return = array('rows' => array(), 'sum' => array());
181 $type = '';
183 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
184 $type = strtolower(
185 substr($row['sql_text'], 0, strpos($row['sql_text'], ' '))
188 switch($type) {
189 case 'insert':
190 case 'update':
191 //Cut off big inserts and updates, but append byte count instead
192 if (strlen($row['sql_text']) > 220) {
193 $implode_sql_text = implode(
194 ' ',
195 PMA_Util::formatByteDown(
196 strlen($row['sql_text']), 2, 2
199 $row['sql_text'] = substr($row['sql_text'], 0, 200)
200 . '... [' . $implode_sql_text . ']';
202 break;
203 default:
204 break;
207 if (! isset($return['sum'][$type])) {
208 $return['sum'][$type] = 0;
210 $return['sum'][$type] += $row['#'];
211 $return['rows'][] = $row;
214 $return['sum']['TOTAL'] = array_sum($return['sum']);
215 $return['numRows'] = count($return['rows']);
217 $GLOBALS['dbi']->freeResult($result);
219 PMA_Response::getInstance()->addJSON('message', $return);
220 exit;
223 if ($_REQUEST['type'] == 'general') {
224 $limitTypes = '';
225 if (isset($_REQUEST['limitTypes']) && $_REQUEST['limitTypes']) {
226 $limitTypes
227 = 'AND argument REGEXP \'^(INSERT|SELECT|UPDATE|DELETE)\' ';
230 $q = 'SELECT TIME(event_time) as event_time, user_host, thread_id, ';
231 $q .= 'server_id, argument, count(argument) as \'#\' ';
232 $q .= 'FROM `mysql`.`general_log` ';
233 $q .= 'WHERE command_type=\'Query\' ';
234 $q .= 'AND event_time > FROM_UNIXTIME(' . $start . ') ';
235 $q .= 'AND event_time < FROM_UNIXTIME(' . $end . ') ';
236 $q .= $limitTypes . 'GROUP by argument'; // HAVING count > 1';
238 $result = $GLOBALS['dbi']->tryQuery($q);
240 $return = array('rows' => array(), 'sum' => array());
241 $type = '';
242 $insertTables = array();
243 $insertTablesFirst = -1;
244 $i = 0;
245 $removeVars = isset($_REQUEST['removeVariables'])
246 && $_REQUEST['removeVariables'];
248 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
249 preg_match('/^(\w+)\s/', $row['argument'], $match);
250 $type = strtolower($match[1]);
252 if (! isset($return['sum'][$type])) {
253 $return['sum'][$type] = 0;
255 $return['sum'][$type] += $row['#'];
257 switch($type) {
258 case 'insert':
259 // Group inserts if selected
260 if ($removeVars
261 && preg_match(
262 '/^INSERT INTO (`|\'|"|)([^\s\\1]+)\\1/i',
263 $row['argument'], $matches
266 $insertTables[$matches[2]]++;
267 if ($insertTables[$matches[2]] > 1) {
268 $return['rows'][$insertTablesFirst]['#']
269 = $insertTables[$matches[2]];
271 // Add a ... to the end of this query to indicate that
272 // there's been other queries
273 $temp = $return['rows'][$insertTablesFirst]['argument'];
274 if ($temp[strlen($temp) - 1] != '.') {
275 $return['rows'][$insertTablesFirst]['argument']
276 .= '<br/>...';
279 // Group this value, thus do not add to the result list
280 continue 2;
281 } else {
282 $insertTablesFirst = $i;
283 $insertTables[$matches[2]] += $row['#'] - 1;
286 // No break here
288 case 'update':
289 // Cut off big inserts and updates,
290 // but append byte count therefor
291 if (strlen($row['argument']) > 220) {
292 $row['argument'] = substr($row['argument'], 0, 200)
293 . '... ['
294 . implode(
295 ' ',
296 PMA_Util::formatByteDown(
297 strlen($row['argument']),
302 . ']';
304 break;
306 default:
307 break;
310 $return['rows'][] = $row;
311 $i++;
314 $return['sum']['TOTAL'] = array_sum($return['sum']);
315 $return['numRows'] = count($return['rows']);
317 $GLOBALS['dbi']->freeResult($result);
319 PMA_Response::getInstance()->addJSON('message', $return);
320 exit;
324 if (isset($_REQUEST['logging_vars'])) {
325 if (isset($_REQUEST['varName']) && isset($_REQUEST['varValue'])) {
326 $value = PMA_Util::sqlAddSlashes($_REQUEST['varValue']);
327 if (! is_numeric($value)) {
328 $value="'" . $value . "'";
331 if (! preg_match("/[^a-zA-Z0-9_]+/", $_REQUEST['varName'])) {
332 $GLOBALS['dbi']->query(
333 'SET GLOBAL ' . $_REQUEST['varName'] . ' = ' . $value
339 $loggingVars = $GLOBALS['dbi']->fetchResult(
340 'SHOW GLOBAL VARIABLES WHERE Variable_name IN'
341 . ' ("general_log","slow_query_log","long_query_time","log_output")',
345 PMA_Response::getInstance()->addJSON('message', $loggingVars);
346 exit;
349 if (isset($_REQUEST['query_analyzer'])) {
350 $return = array();
352 if (strlen($_REQUEST['database'])) {
353 $GLOBALS['dbi']->selectDb($_REQUEST['database']);
356 if ($profiling = PMA_Util::profilingSupported()) {
357 $GLOBALS['dbi']->query('SET PROFILING=1;');
360 // Do not cache query
361 $query = preg_replace(
362 '/^(\s*SELECT)/i',
363 '\\1 SQL_NO_CACHE',
364 $_REQUEST['query']
367 $result = $GLOBALS['dbi']->tryQuery($query);
368 $return['affectedRows'] = $GLOBALS['cached_affected_rows'];
370 $result = $GLOBALS['dbi']->tryQuery('EXPLAIN ' . $query);
371 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
372 $return['explain'][] = $row;
375 // In case an error happened
376 $return['error'] = $GLOBALS['dbi']->getError();
378 $GLOBALS['dbi']->freeResult($result);
380 if ($profiling) {
381 $return['profiling'] = array();
382 $result = $GLOBALS['dbi']->tryQuery(
383 'SELECT seq,state,duration FROM INFORMATION_SCHEMA.PROFILING'
384 . ' WHERE QUERY_ID=1 ORDER BY seq'
386 while ($row = $GLOBALS['dbi']->fetchAssoc($result)) {
387 $return['profiling'][]= $row;
389 $GLOBALS['dbi']->freeResult($result);
392 PMA_Response::getInstance()->addJSON('message', $return);
393 exit;
398 * JS Includes
400 $header = $response->getHeader();
401 $scripts = $header->getScripts();
402 $scripts->addFile('jquery/jquery.tablesorter.js');
403 $scripts->addFile('jquery/jquery.json-2.4.js');
404 $scripts->addFile('jquery/jquery.sortableTable.js');
405 $scripts->addFile('jquery/jquery-ui-timepicker-addon.js');
406 /* < IE 9 doesn't support canvas natively */
407 if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 9) {
408 $scripts->addFile('jqplot/excanvas.js');
410 $scripts->addFile('canvg/canvg.js');
411 // for charting
412 $scripts->addFile('jqplot/jquery.jqplot.js');
413 $scripts->addFile('jqplot/plugins/jqplot.pieRenderer.js');
414 $scripts->addFile('jqplot/plugins/jqplot.canvasTextRenderer.js');
415 $scripts->addFile('jqplot/plugins/jqplot.canvasAxisLabelRenderer.js');
416 $scripts->addFile('jqplot/plugins/jqplot.dateAxisRenderer.js');
417 $scripts->addFile('jqplot/plugins/jqplot.highlighter.js');
418 $scripts->addFile('jqplot/plugins/jqplot.cursor.js');
419 $scripts->addFile('jqplot/plugins/jqplot.byteFormatter.js');
420 $scripts->addFile('date.js');
422 $scripts->addFile('server_status_monitor.js');
423 $scripts->addFile('server_status_sorter.js');
427 * start output
429 $ServerStatusData = new PMA_ServerStatusData();
432 * Output
434 $response->addHTML('<div>');
435 $response->addHTML($ServerStatusData->getMenuHtml());
436 $response->addHTML(PMA_getHtmlForMonitor($ServerStatusData));
437 $response->addHTML(PMA_getHtmlForClientSideDataAndLinks($ServerStatusData));
438 $response->addHTML('</div>');
439 exit;