Skip to content
Browse files

add support for mysql performance_schema query digests (issue #32)

  • Loading branch information...
1 parent 6b1ab8e commit bf1df55ebd67222ce75925931d804d89cc5c24cb @gtowey gtowey committed Aug 1, 2012
View
149 conf/sample.config.inc.php
@@ -41,8 +41,46 @@
'tables' => array(
'global_query_review' => 'fact',
'global_query_review_history' => 'dimension'
- )
+ ),
+ 'source_type' => 'slow_query_log'
+);
+
+/**
+ * If you're using Anemometer with MySQL 5.6's performance schema,
+ * then use this datasource
+ *
+$conf['datasources']['mysql56'] = array(
+ 'host' => 'localhost',
+ 'port' => 3306,
+ 'db' => 'performance_schema',
+ 'user' => 'root',
+ 'password' => '',
+ 'tables' => array(
+ 'events_statements_summary_by_digest' => 'fact',
+ ),
+ 'source_type' => 'performance_schema'
+);
+*/
+
+/**
+ * if you're collecting history form the performance_schema table and
+ * saving it, then use this datasource which will allow you to see graphs
+ * and query details. By using an additional process to save performance schema
+ * data, you can insert it into a table structure similar to that used by
+ * pt-query-digest.
+$conf['datasources']['localhost_history'] = array(
+ 'host' => 'localhost',
+ 'port' => 3306,
+ 'db' => 'slow_query_log',
+ 'user' => 'root',
+ 'password' => '',
+ 'tables' => array(
+ 'events_statements' => 'fact',
+ 'events_statements_history' => 'dimension'
+ ),
+ 'source_type' => 'performance_schema_history'
);
+**/
/**
@@ -120,6 +158,46 @@
'plot_field' => 'Query_time_sum',
);
+// these are the default values for mysql 5.6 performance schema datasources
+$conf['report_defaults']['performance_schema'] = array(
+ 'fact-order' => 'SUM_TIMER_WAIT DESC',
+ 'fact-limit' => '20',
+ 'table_fields' => array( 'DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' )
+);
+
+// these are the default values for using performance schema to save your own
+// query history in a table structure similar to percona's pt-query-digest format
+$conf['report_defaults']['performance_schema_history'] = array(
+ 'fact-group' => 'DIGEST',
+ 'fact-order' => 'SUM_TIMER_WAIT DESC',
+ 'fact-limit' => '20',
+ 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-1 day')),
+ 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"),
+ 'table_fields' => array( 'DIGEST', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' )
+);
+
+$conf['graph_defaults']['performance_schema_history'] = array(
+ 'fact-group' => 'hour_ts',
+ 'fact-order' => 'hour_ts',
+ 'fact-limit' => '',
+ 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-7 day')),
+ 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"),
+ 'table_fields' => array('hour_ts'),
+ // hack ... fix is to make query builder select the group and order fields,
+ // then table fields only has to contain the plot_field
+ 'plot_field' => 'SUM_TIMER_WAIT',
+ 'dimension-pivot-hostname_max' => null
+);
+
+$conf['history_defaults']['performance_schema_history'] = array(
+ 'output' => 'table',
+ 'fact-group' => 'date',
+ 'fact-order' => 'date DESC',
+ 'fact-limit' => '90',
+ 'dimension-FIRST_SEEN_start' => date("Y-m-d H:i:s", strtotime( '-90 day')),
+ 'dimension-FIRST_SEEN_end' => date("Y-m-d H:i:s"),
+ 'table_fields' => array( 'date', 'snippet', 'index_ratio', 'COUNT_STAR', 'SUM_LOCK_TIME','SUM_ROWS_AFFECTED','SUM_ROWS_SENT','SUM_ROWS_EXAMINED','SUM_CREATED_TMP_TABLES','SUM_SORT_SCAN','SUM_NO_INDEX_USED' )
+);
/**
* Plugins are optional extra information that can be displayed, but often
* relies on information specific to your system, and has to be set manually.
@@ -261,6 +339,75 @@
);
+$conf['reports']['performance_schema'] = array(
+ // form fields
+ 'fields' => array(
+ 'fact' => array(
+ //'group' => 'group',
+ 'order' => 'order',
+ 'having' => 'having',
+ 'limit' => 'limit',
+ 'first_seen' => 'date_range|reldate|clear|where',
+ 'where' => 'raw_where',
+ 'DIGEST' => 'clear|where',
+ 'DIGEST_TEXT' => 'clear|like|where',
+ ),
+ ),
+ // custom fields
+ 'custom_fields' => array(
+ 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)',
+ 'index_ratio' =>'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)',
+ 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)',
+
+ ),
+);
+
+$conf['reports']['performance_schema_history'] = array(
+ // joins
+ 'join' => array (
+ 'dimension' => 'USING (`DIGEST`)'
+ ),
+
+ // form fields
+ 'fields' => array(
+ 'fact' => array(
+ 'group' => 'group',
+ 'order' => 'order',
+ 'having' => 'having',
+ 'limit' => 'limit',
+ 'first_seen'=> 'clear|reldate|ge|where',
+ 'where' => 'raw_where',
+ 'DIGEST_TEXT' => 'clear|like|where',
+ 'DIGEST' => 'clear|where',
+ 'reviewed_status' => 'clear|where',
+
+ ),
+
+ 'dimension' => array(
+ 'extra_fields' => 'where',
+ 'hostname' => 'clear|where',
+ 'FIRST_SEEN' => 'date_range|reldate|clear|where',
+ 'pivot-hostname' => 'clear|pivot|select',
+ ),
+ ),
+ // custom fields
+ 'custom_fields' => array(
+ 'date' => 'DATE(fact.FIRST_SEEN)',
+ 'snippet' => 'LEFT(fact.DIGEST_TEXT,20)',
+ 'index_ratio' =>'ROUND(SUM_ROWS_EXAMINED/SUM_ROWS_SENT,2)',
+ 'rows_sent_avg' => 'ROUND(SUM_ROWS_SENT/COUNT_STAR,0)',
+ 'hour' => 'substring(dimension.FIRST_SEEN,1,13)',
+ 'hour_ts' => 'unix_timestamp(substring(dimension.FIRST_SEEN,1,13))',
+ ),
+
+ 'special_field_names' => array(
+ 'time' => 'FIRST_SEEN',
+ 'checksum' => 'DIGEST',
+ 'hostname' => 'hostname',
+ 'sample' => 'DIGEST_TEXT'
+ )
+);
+
/**
* end of configuration settings
*/
View
2 index.php
@@ -12,7 +12,7 @@
require "Helpers.php";
require "Anemometer.php";
-error_reporting(E_ERROR);
+error_reporting(E_ALL);
$action = isset($_GET['action']) ? $_GET['action'] : 'index';
$conf = array();
View
140 lib/Anemometer.php
@@ -60,11 +60,12 @@ public function api()
{
// special case for optional pivot on hostname
// mainly used to graph each host as a series
- if (get_var('dimension-pivot-hostname_max') != null)
+ $hostname_field = $this->data_model->get_field_name('hostname');
+ if (get_var('dimension-pivot-'.$hostname_field) != null)
{
$dimension_table = $this->report_obj->get_table_by_alias('dimension');
- $hosts = $this->report_obj->get_distinct_values($dimension_table, 'hostname_max');
- $this->report_obj->set_pivot_values('dimension-pivot-hostname_max', $hosts);
+ $hosts = $this->report_obj->get_distinct_values($dimension_table, $hostname_field);
+ $this->report_obj->set_pivot_values('dimension-pivot-'.$hostname_field, $hosts);
}
// process the form data, and get the query result
@@ -114,13 +115,18 @@ public function graph_search()
$this->header();
$this->set_search_defaults('graph_defaults');
$data['datasource'] = get_var('datasource');
+
+ $data['time_field_name'] = $time = $this->data_model->get_field_name('time');
+ $data['hostname_field_name'] = $this->data_model->get_field_name('hostname');
+ $data['checksum_field_name'] = $this->data_model->get_field_name('checksum');
// get table and hostname data for search form
$data['tables'] = $this->report_obj->get_tables();
$dimension_table = $this->report_obj->get_table_by_alias('dimension');
- $data['hosts'] = $this->report_obj->get_distinct_values($dimension_table, 'hostname_max');
- $data['hostname_max'] = get_var('dimension-hostname_max');
- $this->report_obj->set_pivot_values('dimension-pivot-hostname_max', $data['hosts']);
+ $data['hosts'] = $this->report_obj->get_distinct_values($dimension_table, $data['hostname_field_name']);
+ // check
+ $data[$data['hostname_field_name']] = get_var($data['hostname_field_name']);
+ $this->report_obj->set_pivot_values('dimension-pivot-'.$data['hostname_field_name'], $data['hosts']);
// get custom fields for search form
foreach ($data['tables'] as $t) {
@@ -131,23 +137,22 @@ public function graph_search()
// process the form data so we can get the ajax url
$this->report_obj->process_form_data();
$_GET['table_fields'][] = get_var('plot_field');
- if (get_var('dimension-pivot-hostname_max')) {
- $_GET['dimension-pivot-hostname_max'] = get_var('plot_field');
+ if (get_var('dimension-pivot-'.$data['hostname_field_name'])) {
+ $_GET['dimension-pivot-'.$data['hostname_field_name']] = get_var('plot_field');
$data['dimension_pivot_hostname_max'] = get_var('plot_field');
}
- $data['ajax_request_url'] = site_url() . '?action=api&output=json2&noheader=1&datasource=' . $data['datasource'] . '&' . $this->report_obj->get_search_uri(array( 'dimension-ts_min' ));
- $data['graph_permalink'] = site_url() . '?action=graph_search&datasource=' . $data['datasource'] . '&plot_field='.get_var('plot_field').'&'.$this->report_obj->get_search_uri(array( 'dimension-ts_min' ));
+ $data['ajax_request_url'] = site_url() . '?action=api&output=json2&noheader=1&datasource=' . $data['datasource'] . '&' . $this->report_obj->get_search_uri(array( 'dimension-'.$time));
+ $data['graph_permalink'] = site_url() . '?action=graph_search&datasource=' . $data['datasource'] . '&plot_field='.get_var('plot_field').'&'.$this->report_obj->get_search_uri(array( 'dimension-'.$time ));
// now go get a url for the table results
$this->init_report();
- $this->set_search_defaults('report_defaults', array('dimension-ts_min_start', 'dimension-ts_min_end','checksum'));
+ $this->set_search_defaults('report_defaults', array('dimension-'.$time.'_start', 'dimension-'.$time.'_end', $data['checksum_field_name']));
// $data['ajax_request_url_table'] = site_url() . '?action=api&output=table&noheader=1&datasource=' . $data['datasource'] . '&' . $this->report_obj->get_search_uri();
- $_GET['fact-order'] = get_var('plot_field') . ' DESC';
- $data['ajax_table_request_url_base'] = site_url() . '?action=api&output=table&noheader=1&datasource=' . $data['datasource']. '&' . $this->report_obj->get_search_uri(array( 'dimension-ts_min' ));
- $data['table_url_time_start_param'] = 'dimension-ts_min_start';
- $data['table_url_time_end_param'] = 'dimension-ts_min_end';
-
+ $_GET['fact-order'] = get_var('plot_field') . ' DESC';
+ $data['ajax_table_request_url_base'] = site_url() . '?action=api&output=table&noheader=1&datasource=' . $data['datasource']. '&' . $this->report_obj->get_search_uri(array( 'dimension-'.$data['time_field_name']));
+ $data['table_url_time_start_param'] = 'dimension-'.$data['time_field_name'].'_start';
+ $data['table_url_time_end_param'] = 'dimension-'.$data['time_field_name'].'_end';
// display the page
$this->load->view("graph_search", $data);
@@ -221,9 +226,11 @@ public function report() {
$data['datasource'] = get_var('datasource');
$data['tables'] = $this->report_obj->get_tables();
- $data['hosts'] = $this->report_obj->get_distinct_values($data['tables'][1], 'hostname_max');
- $data['hostname_max'] = get_var('dimension-hostname_max');
- $this->report_obj->set_pivot_values('dimension-pivot-hostname_max', $data['hosts']);
+
+ $fieldname = $this->data_model->get_field_name('hostname');
+ $data['hosts'] = $this->report_obj->get_distinct_values($data['tables'][1], $fieldname);
+ $data[$fieldname] = get_var('dimension-'.$fieldname);
+ $this->report_obj->set_pivot_values('dimension-pivot-'.$fieldname, $data['hosts']);
// $data['fields = $this->report_obj->get_form_fields();
// @todo remove
@@ -238,8 +245,7 @@ public function report() {
$data['review_types'] = $this->data_model->get_review_types();
$data['reviewers'] = $this->data_model->get_reviewers();
-
- $this->load->view("report", $data);
+ $this->display_report_form($data);
}
// just call the api to process and display report
@@ -294,7 +300,8 @@ public function show_query() {
$data = array();
$data['checksum'] = $checksum;
$data['datasource'] = get_var('datasource');
-
+ $sample_field_name = $this->data_model->get_field_name('sample');
+
// query and most recent sample
$data['row'] = $this->data_model->get_query_by_checksum($checksum);
$data['sample'] = $this->data_model->get_query_samples($checksum, 1)->fetch_assoc();
@@ -304,22 +311,33 @@ public function show_query() {
$data['reviewers'] = $this->data_model->get_reviewers();
$data['current_auth_user'] = $this->get_auth_user();
+ $sample = $data['sample'][$sample_field_name];
// get explain plan and extra info
// TODO convert to ajax calls, just get the url
- try
- {
- $this->data_model->init_query_explainer($data['sample']);
- }
- catch ( Exception $e )
- {
- $data['explain_plan_error'] = $e->getMessage();
- }
- $data['explain_plan'] = $this->data_model->get_explain_for_sample($data['sample']);
- $data['visual_explain'] = $this->data_model->get_visual_explain($data['explain_plan']);
- $sample = $data['sample']['sample'];
- $data['query_advisor'] = $this->data_model->get_query_advisor($sample);
- $data['create_table'] = $this->data_model->get_create_table($sample);
- $data['table_status'] = $this->data_model->get_table_status($sample);
+ $source_type = $this->data_model->get_source_type();
+
+ $data['show_samples'] = true;
+ if ($source_type == 'performance_schema_history')
+ {
+ $data['show_samples'] = false;
+ $data['row']['fingerprint'] = $sample;
+ }
+ else
+ {
+ try
+ {
+ $this->data_model->init_query_explainer($data['sample']);
+ }
+ catch ( Exception $e )
+ {
+ $data['explain_plan_error'] = $e->getMessage();
+ }
+ $data['explain_plan'] = $this->data_model->get_explain_for_sample($data['sample']);
+ $data['visual_explain'] = $this->data_model->get_visual_explain($data['explain_plan']);
+ $data['query_advisor'] = $this->data_model->get_query_advisor($sample);
+ $data['create_table'] = $this->data_model->get_create_table($sample);
+ $data['table_status'] = $this->data_model->get_table_status($sample);
+ }
// graph
$this->set_search_defaults('graph_defaults');
@@ -328,6 +346,12 @@ public function show_query() {
$_GET['fact-checksum'] = $checksum;
$data['ajax_request_url'] = site_url() . '?action=api&output=json2&noheader=1&datasource=' . $data['datasource'] . '&' . $this->report_obj->get_search_uri();
+ $data['sample_field_name'] = $this->data_model->get_field_name('sample');
+ $data['hostname_field_name'] =$this->data_model->get_field_name('hostname');
+ $data['time_field_name'] =$this->data_model->get_field_name('time');
+
+
+
$this->load->view("show_query", $data);
// Show the history for this query
@@ -389,6 +413,29 @@ private function alert($string, $level = 'alert-warning') {
$this->header();
print "<div class=\"alert {$level}\">{$string}</div>";
}
+
+ private function display_report_form($data)
+ {
+ $data['hostname_field_name'] = $this->data_model->get_field_name('hostname');
+ $data['checksum_field_name'] = $this->data_model->get_field_name('checksum');
+ $data['time_field_name'] = $this->data_model->get_field_name('time');
+ $data['sample_field_name'] = $this->data_model->get_field_name('sample');
+ if (!is_object($this->data_model))
+ {
+ throw new Exception("No datasource defined");
+ }
+
+ $source_type = $this->data_model->get_source_type();
+ switch ($source_type)
+ {
+ case 'performance_schema':
+ $this->load->view("report-performance_schema", $data);
+ break;
+ default:
+ $this->load->view("report", $data);
+ break;
+ }
+ }
/**
* display the global web application footer
@@ -402,7 +449,17 @@ private function footer() {
* from the session if possible.
*/
private function get_auth_user() {
- return isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : $_SESSION['current_review_user'];
+ if (array_key_exists('PHP_AUTH_USER', $_SERVER))
+ {
+ return $_SERVER['PHP_AUTH_USER'];
+
+ }
+ else if (array_key_exists('current_review_user', $_SESSION))
+ {
+ return $_SESSION['current_review_user'];
+ }
+
+ return null;
}
/**
@@ -413,15 +470,19 @@ private function header() {
if ($this->header_printed) {
return false;
}
+ $datasources = null;
+ $datasource = null;
+ $source_type = null;
if (is_object($this->data_model))
{
$datasources = $this->data_model->get_data_source_names();
$datasource = get_var('datasource');
+ $source_type = $this->data_model->get_source_type();
}
if (!get_var('noheader')) {
$this->load->view("header");
- $this->load->view("navbar", array( 'datasources' => $datasources, 'datasource' => $datasource ));
+ $this->load->view("navbar", array( 'datasources' => $datasources, 'datasource' => $datasource, 'source_type' => $source_type ));
}
$this->header_printed = true;
@@ -433,14 +494,15 @@ private function header() {
*/
private function init_report() {
$datasource = get_var('datasource');
+
if (isset($datasource)) {
$conf = $this->data_model->get_data_source($datasource);
// create report object ... try to minimize overlap of responsibilities.
$this->report_obj = new MySQLTableReport(
$conf,
$conf['tables'],
- $this->data_model->get_report('slow_query_log')
+ $this->data_model->get_report($conf['source_type'])
);
}
}
View
89 lib/AnemometerModel.php
@@ -45,7 +45,30 @@ public function get_default_report_action() {
* @return array The default values for the search form
*/
public function get_report_defaults($type = 'report_defaults') {
- return $this->conf[$type];
+ if (!isset($this->datasource_name))
+ {
+ throw new Exception("Cannot get report default values without a datasource defined");
+ }
+ $source_type = $this->conf['datasources'][$this->datasource_name]['source_type'];
+
+ // for backwards compatability with conf files.
+ if (array_key_exists($type, $this->conf) and array_key_exists($source_type, $this->conf[$type]))
+ {
+ return $this->conf[$type][$source_type];
+ }
+ else
+ {
+ return $this->conf[$type];
+ }
+ }
+
+ public function get_source_type()
+ {
+ if (isset($this->datasource_name) and array_key_exists('source_type', $this->conf['datasources'][$this->datasource_name]))
+ {
+ return $this->conf['datasources'][$this->datasource_name]['source_type'];
+ }
+ return 'default';
}
/**
@@ -96,6 +119,24 @@ public function set_data_source($name) {
$this->dimension_table = $key;
}
}
+
+ if (array_key_exists('source_type', $this->conf['datasources'][$name]) and $this->conf['datasources'][$name]['source_type'] == 'performance_schema')
+ {
+ // check for correct mysql version with performance schema source type
+ $this->connect_to_datasource();
+ $result = $this->mysqli->query("SELECT @@version");
+ $version = 'unknown';
+ if (is_object($result))
+ {
+ $row = $result->fetch_assoc();
+ if ($row['@@version'] >= '5.6')
+ {
+ return true;
+ }
+ $version = $row['@@version'];
+ }
+ throw new Exception("Datasource {$name} has a source_type of performance_schema which requires mysql version >= 5.6. Found version: {$version}");
+ }
}
/**
@@ -128,7 +169,11 @@ public function get_form_fields($name) {
* @return array The configuration information
*/
public function get_report($name) {
- return $this->conf['reports'][$name];
+ if (isset($name))
+ {
+ return $this->conf['reports'][$name];
+ }
+ return $this->conf['reports']['slow_query_log'];
}
/**
@@ -147,7 +192,9 @@ public function get_reviewers() {
* @return boolean true if it exists, otherwise false
*/
public function checksum_exists($checksum) {
- $result = $this->mysqli->query("SELECT checksum FROM {$this->fact_table} WHERE checksum='" . $this->mysqli->real_escape_string($checksum) . "'");
+ $checksum_field_name = $this->get_field_name('checksum');
+ $query = "SELECT {$checksum_field_name} FROM {$this->fact_table} WHERE {$checksum_field_name}='" . $this->mysqli->real_escape_string($checksum) . "'";
+ $result = $this->mysqli->query($query);
check_mysql_error($result, $this->mysqli);
if ($result->num_rows) {
return true;
@@ -163,6 +210,7 @@ public function checksum_exists($checksum) {
*/
public function update_query($checksum, $fields) {
$mysqli = $this->mysqli;
+ $checksum_field_name = $this->get_field_name('checksum');
$sql = "UPDATE {$this->fact_table} SET ";
$sql .= join(
',', array_map(
@@ -174,7 +222,7 @@ function ($x, $y) use ($mysqli) {
}, array_keys($fields), array_values($fields)
)
);
- $sql .= " WHERE checksum='" . $this->mysqli->real_escape_string($checksum) . "'";
+ $sql .= " WHERE {$checksum_field_name}='" . $this->mysqli->real_escape_string($checksum) . "'";
$res = $this->mysqli->query($sql);
// @todo ... fix this by making it a local method
check_mysql_error($res, $this->mysqli);
@@ -187,7 +235,8 @@ function ($x, $y) use ($mysqli) {
* @return mixed The row of data, or null
*/
public function get_query_by_checksum($checksum) {
- $result = $this->mysqli->query("SELECT * FROM {$this->fact_table} WHERE checksum={$checksum}");
+ $checksum_field_name = $this->get_field_name('checksum');
+ $result = $this->mysqli->query("SELECT * FROM {$this->fact_table} WHERE {$checksum_field_name}='{$checksum}'");
check_mysql_error($result, $this->mysqli);
if ($row = $result->fetch_assoc()) {
return $row;
@@ -204,7 +253,9 @@ public function get_query_by_checksum($checksum) {
* @return MySQLi_Result The result handle
*/
public function get_query_samples($checksum, $limit = 1, $offset = 0) {
- $sql = "SELECT ts_min, ts_max, db_max, hostname_max, sample FROM {$this->dimension_table} WHERE checksum=$checksum ORDER BY ts_max DESC LIMIT {$limit} OFFSET {$offset}";
+ $checksum_field_name = $this->get_field_name('checksum');
+ $time_field_name = $this->get_field_name('time');
+ $sql = "SELECT * FROM {$this->dimension_table} WHERE {$checksum_field_name}='{$checksum}' ORDER BY {$time_field_name} DESC LIMIT {$limit} OFFSET {$offset}";
return $this->mysqli->query($sql);
}
@@ -347,7 +398,31 @@ public function get_table_status($query) {
return $this->explainer->get_table_status($query);
}
-
+
+ public function get_field_name($type)
+ {
+ if (!isset($this->datasource_name))
+ {
+ throw new Exception("Cannot get report special field names without a datasource defined");
+ }
+ $source_type = $this->conf['datasources'][$this->datasource_name]['source_type'];
+
+ if (array_key_exists('special_field_names', $this->conf['reports'][$source_type]))
+ {
+ return $this->conf['reports'][$source_type]['special_field_names'][$type];
+ }
+
+ // backwards compatability
+ switch ($type)
+ {
+ case 'time':
+ return 'ts_min';
+ case 'hostname':
+ return 'hostname_max';
+ case 'checksum':
+ return 'checksum';
+ }
+ }
}
?>
View
54 lib/MySQLTableReport.php
@@ -178,7 +178,11 @@ public function set_pivot_values($col_name, array $values) {
* @return array the list of values defined by set_pivot_values
*/
public function get_pivot_values($col_name) {
- return $this->pivot[$col_name];
+ if (array_key_exists($col_name, $this->pivot))
+ {
+ return $this->pivot[$col_name];
+ }
+ return array();
}
/**
@@ -317,11 +321,13 @@ public function get_table_fields($table_name = null) {
* @return array the list of unique values
*/
public function get_distinct_values($table, $colname) {
- //print "getting distinct $colname from $table<br>";
$result = $this->mysqli->query("SELECT DISTINCT `{$colname}` FROM `{$table}`");
$values = array();
- while ($row = $result->fetch_array()) {
- $values[] = $row[0];
+ if (is_object($result))
+ {
+ while ($row = $result->fetch_array()) {
+ $values[] = $row[0];
+ }
}
return $values;
}
@@ -699,11 +705,29 @@ public function like($col_name, $var_name, $expression) {
* @return null|string
*/
private function get_column_aggregate_function($name) {
- if (!preg_match("/_([^_]+)$/", $name, $regs)) {
+
+ if (!preg_match("/^([^_]+)_?.*_([^_]+)$/", $name, $regs)) {
return null;
}
- switch ($regs[1]) {
+ //print $regs[1].":". $regs[2]."<br>\n";
+ switch ($regs[1])
+ {
+ case 'SUM':
+ case 'COUNT':
+ return 'SUM';
+ case 'AVG':
+ return 'AVG';
+ case 'MIN':
+ case 'FIRST':
+ return 'MIN';
+ case 'MAX':
+ case 'LAST':
+ return 'MAX';
+ }
+
+
+ switch ($regs[2]) {
case 'sum':
case 'cnt':
return 'SUM';
@@ -736,13 +760,21 @@ public function process_form_data() {
// SELECT
$select = array();
- foreach (get_var('table_fields') as $f) {
- if (isset($this->report['custom_fields'][$f])) {
- $select[$f] = array($this->report['custom_fields'][$f], $f, null);
- } else {
- $select[$f] = array($f, null, $this->get_column_aggregate_function($f));
+ $fields = get_var('table_fields');
+ if (isset($fields) and is_array($fields) and count($fields) > 0)
+ {
+ foreach ($fields as $f) {
+ if (isset($this->report['custom_fields'][$f])) {
+ $select[$f] = array($this->report['custom_fields'][$f], $f, null);
+ } else {
+ $select[$f] = array($f, null, $this->get_column_aggregate_function($f));
+ }
}
}
+ else
+ {
+ throw new Exception("No fields selected");
+ }
foreach ($select as $field => $spec) {
$this->select($spec[0], $spec[1], $spec[2]);
View
46 mysql56-install.sql
@@ -0,0 +1,46 @@
+CREATE DATABASE IF NOT EXISTS slow_query_log;
+CREATE TABLE events_statements (
+ `DIGEST` varchar(32) character set binary NOT NULL ,
+ `DIGEST_TEXT` longtext NOT NULL,
+ `first_seen` datetime DEFAULT NULL,
+ `last_seen` datetime DEFAULT NULL,
+ `reviewed_by` varchar(20) DEFAULT NULL,
+ `reviewed_on` datetime DEFAULT NULL,
+ `reviewed_status` varchar(24) DEFAULT NULL,
+ `comments` text,
+ PRIMARY KEY (`DIGEST`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE events_statements_history (
+ history_id bigint unsigned not null auto_increment PRIMARY KEY,
+ hostname varchar(48) not null default '',
+ `DIGEST` varchar(32) character set binary DEFAULT NULL ,
+ `DIGEST_TEXT` longtext,
+ `COUNT_STAR` bigint(20) unsigned NOT NULL,
+ `SUM_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `MIN_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `AVG_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `MAX_TIMER_WAIT` bigint(20) unsigned NOT NULL,
+ `SUM_LOCK_TIME` bigint(20) unsigned NOT NULL,
+ `SUM_ERRORS` bigint(20) unsigned NOT NULL,
+ `SUM_WARNINGS` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_AFFECTED` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_SENT` bigint(20) unsigned NOT NULL,
+ `SUM_ROWS_EXAMINED` bigint(20) unsigned NOT NULL,
+ `SUM_CREATED_TMP_DISK_TABLES` bigint(20) unsigned NOT NULL,
+ `SUM_CREATED_TMP_TABLES` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_FULL_JOIN` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_FULL_RANGE_JOIN` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_RANGE` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_RANGE_CHECK` bigint(20) unsigned NOT NULL,
+ `SUM_SELECT_SCAN` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_MERGE_PASSES` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_RANGE` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_ROWS` bigint(20) unsigned NOT NULL,
+ `SUM_SORT_SCAN` bigint(20) unsigned NOT NULL,
+ `SUM_NO_INDEX_USED` bigint(20) unsigned NOT NULL,
+ `SUM_NO_GOOD_INDEX_USED` bigint(20) unsigned NOT NULL,
+ `FIRST_SEEN` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `LAST_SEEN` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+ UNIQUE KEY (`DIGEST`, `hostname`, FIRST_SEEN, LAST_SEEN )
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
View
12 mysql56-save_history.sql
@@ -0,0 +1,12 @@
+USE DB slow_query_log;
+
+CREATE TEMPORARY TABLE `statements_temp` SELECT * FROM performance_schema.events_statements_summary_by_digest;
+
+INSERT INTO events_statements (DIGEST, DIGEST_TEXT, first_seen, last_seen) SELECT DIGEST, DIGEST_TEXT, FIRST_SEEN, LAST_SEEN FROM statements_temp ON DUPLICATE KEY UPDATE first_seen=LEAST(VALUES(events_statements.first_seen), events_statements.first_seen), last_seen=GREATEST(VALUES(events_statements.last_seen),events_statements.last_seen);
+
+SELECT CONCAT('INSERT IGNORE INTO events_statements_history (', GROUP_CONCAT(DISTINCT a.column_name),',hostname) SELECT ', GROUP_CONCAT(DISTINCT a.column_name),', @@hostname FROM statements_temp') INTO @stmt from information_schema.columns a JOIN information_schema.columns b ON a.column_name=b.column_name and b.table_name='events_statements_history' where a.table_schema='performance_schema' and a.table_name='events_statements_summary_by_digest';
+PREPARE stmt FROM @stmt;
+EXECUTE @stmt;
+
+DROP TABLE IF EXISTS statements_temp;
+TRUNCATE TABLE performance_schema.events_statements_summary_by_digest;
View
286 views/graph_search-performance_schema_history.php
@@ -0,0 +1,286 @@
+<div class="row">
+ <form action="<?php echo site_url() ?>" method="GET" class="form-inline">
+ <input type="hidden" name="action" value="graph_search">
+ <input type="hidden" name="datasource" value="<?php echo $datasource; ?>">
+ <div class="row">
+ <div class="span3">
+ From<br>
+ <div class="input-append">
+ <input type="text" class="span2" name="dimension-ts_min_start" id="dimension-ts_min_start" value="<?php echo get_var('dimension-ts_min_start'); ?>">
+ <span class="add-on"><i class="icon-calendar" id="dp"></i></span>
+ </div>
+ </div>
+
+ <div class="span4">
+ To<br>
+ <div class="input-append">
+ <input type="text" class="span2" name="dimension-ts_min_end" id="dimension-ts_min_end" value="<?php echo get_var('dimension-ts_min_end'); ?>">
+ <span class="add-on"><i class="icon-calendar" id="dp"></i></span>
+ </div>
+ </div>
+
+ <div class="span4">
+ Column to plot<br>
+ <select name="plot_field" class="span3">
+ <optgroup label="Custom Fields">
+ <?php foreach ($custom_fields as $f) { ?>
+ <option value="<?php echo $f ?>" <?php if (get_var('plot_field') == $f) { echo "SELECTED"; } ?>><?php echo $f ?></option>
+ <?php } ?>
+ </optgroup>
+
+ <?php foreach (array_keys($table_fields) as $table) { ?>
+ <optgroup label="<?php echo $table; ?>">
+ <?php foreach ($table_fields[$table] as $f) { ?>
+ <option value="<?php echo $f ?>" <?php if (get_var('plot_field') == $f) { echo "SELECTED"; } ?>><?php echo $f ?></option>
+ <?php } ?>
+ </optgroup>
+ <?php } ?>
+ </select>
+ </div>
+ </div>
+ <div class="row">
+ <div class="span3" >
+ Filter By Host<br>
+ <select name="dimension-hostname_max" class="span3 combobox">
+ <option value=""></option>
+ <?php foreach ($hosts as $h) { ?>
+ <option value="<?php echo $h ?>" <?php if (isset($hostname_max) AND $hostname_max == $h ) { echo "SELECTED"; } ?>><?php echo $h ?></option>
+ <?php } ?>
+ </select>
+ </div>
+
+ <div class="span4" >
+ <input type="checkbox" name="dimension-pivot-hostname_max" value='ts_cnt'<?php echo (isset($dimension_pivot_hostname_max) ? ' CHECKED ' : '') ?>> Show each host as a separate series
+
+ </div>
+
+ <div class="span4">
+
+ <input type="submit" class="btn-primary btn-large" name="submit" value="Search">
+
+ </div>
+ </div>
+
+ </form>
+</div>
+<hr>
+
+<div class="row">
+ <div id="theplot" class="span12" style="height: 300px;"></div>
+</div>
+<div class="row">
+ <p>You selected: <span id="selection"></span></p>
+ <p><a id="reset_selection" value="Clear selection" class="btn" href="#"><i class="icon-fire"></i> Reset Selection</a>
+ <a id="permalink_btn" class="btn" href="#"><i class="icon-magnet"></i> Graph Permalink</a></p>
+</div>
+<hr>
+ </div></div>
+<span id="report_table"><center><img src="img/ajax-loader.gif"></center></div>
+
+<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.js"></script>
+<script language="javascript" type="text/javascript" src="js/flot/jquery.flot.selection.js"></script>
+<script>
+// urls to retrieve data from
+var GRAPH_DATA_URL = "<?php echo $ajax_request_url ?>";
+var GRAPH_PERMALINK_URL = "<?php echo $graph_permalink; ?>";
+var TABLE_BASE_URL = "<?php echo $ajax_table_request_url_base ?>"
+var TABLE_URL_TIME_START_PARAM = "<?php echo $table_url_time_start_param ?>"
+var TABLE_URL_TIME_END_PARAM = "<?php echo $table_url_time_end_param ?>"
+
+// Setup options for the plot
+var FLOT_OPTS = {
+ series: {
+ lines: { show: true }, // line graphs!
+ points: { show: true}, // draw individual data points
+ },
+ legend: { noColumns: 2 },
+ xaxis: { tickDecimals: 0, mode: "time" },
+ yaxis: { min: 0 },
+ selection: { mode: "x" }, // any mouse selections should be along x axis
+};
+
+// Placeholder for data to plot
+var DATA = [];
+
+
+/**
+ * Callback function for drawing the graph after data is retrieved from an AJAX call
+ * @param data The array of objects containing time series data to plot.
+ */
+function new_plot_data(data) {
+ // flot requires millseconds, so convert the timestamp from seconds to milliseconds
+ for ( var i = 0; i < data.length; i++ )
+ {
+ for ( var j = 0; j < data[i].data.length; j++ )
+ {
+ data[i].data[j][0] = data[i].data[j][0] * 1000;
+ data[i].data[j][0] = data[i].data[j][0] - (60*60*7*1000);
+ }
+ }
+ var theplot = $("#theplot"); // get the graph div
+ DATA = data;
+ plot_obj = $.plot(theplot, DATA, FLOT_OPTS);
+ setup_selection(theplot);
+}
+
+/**
+ * Function to left pad a value (needed for date padding)
+ * @param pad_this the data to pad (this will be converted to a string)
+ * @param padding a string of what to left pad the data with
+ * @param amount how much padding to apply.
+ */
+function left_pad(pad_this, padding, amount)
+{
+ var s = String(pad_this);
+ var padded_str = '';
+ if(s.length < amount)
+ {
+ for ( var i = 1; i < amount; i++)
+ {
+ padded_str += padding;
+ }
+ padded_str += pad_this;
+ }
+ else
+ {
+ padded_str += pad_this;
+ }
+ return padded_str;
+}
+
+/**
+ * convert a date object to an ANSI-compliant date string (e.g. YYYY-mm-dd HH:MM:ss)
+ * @param d the javascript Date object
+ */
+function to_sql_date(d)
+{
+ // put the year together in the form of YYYY-MM-DD
+ ansi_date = d.getFullYear() + '-' + left_pad(d.getMonth()+1, '0', 2) + '-' + left_pad(d.getDate(), '0', 2);
+ ansi_date += ' ';
+ // put the time together as HH:MM:ss and append to the year
+ ansi_date += left_pad(d.getHours(), '0', 2) + ':' + left_pad(d.getMinutes(), '0', 2) + ':' + left_pad(d.getSeconds(), '0', 2);
+ return ansi_date;
+}
+
+/**
+ * Register an event listener on the div with the flot graph so selection events
+ * from the mouse can be registered for "zoom in" functionality.
+ * @param theplot a JQuery object of the div containing the flot graph.
+*/
+function setup_selection(theplot) {
+ theplot.bind("plotselected", function (event, ranges) {
+ var plot = $.plot(theplot, DATA, $.extend ( true, {}, FLOT_OPTS, {
+ xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
+ }));
+
+ // need a date object to shove timestamp into for conversion to ANSI-type date string
+ d = new Date();
+
+ // get start datetime for selected fields
+ d.setTime(Math.floor(ranges.xaxis.from + (60*60*7*1000)));
+ start_time = to_sql_date(d);
+
+ // get end datetime for selected fields
+ d.setTime(Math.floor(ranges.xaxis.to + (60*60*7*1000)));
+ end_time = to_sql_date(d);
+
+ // construct a url with the new time frame the graph is focused on to populate the table on the page.
+ var new_url_start_end_params = '&' + escape(TABLE_URL_TIME_START_PARAM) + '=' + escape(start_time) + '&' + escape(TABLE_URL_TIME_END_PARAM) + '=' + escape(end_time);
+ var new_table_data_url = TABLE_BASE_URL + new_url_start_end_params;
+
+ // Plop a shiny loading spinner in place of the table until the AJAX call finishes :)
+ $('#report_table').html('<center><img src="img/ajax-loader.gif"></center>');
+
+ // Update the permalink button
+ $('#permalink_btn').attr('href', GRAPH_PERMALINK_URL + new_url_start_end_params);
+
+ // Get the data for the table and re-populate it!
+ $.ajax({
+ url: new_table_data_url,
+ method: 'GET',
+ dataType: 'html',
+ success: show_table_data
+ });
+
+ // Throw the selected time values just under the graph for clarity
+ $('#selection').text(start_time + " to " + end_time);
+ $('#dimension-ts_min_start').val(start_time);
+ $('#dimension-ts_min_end').val(end_time);
+ });
+
+ theplot.bind("plotunselected", function (event) {
+ $("#selection").text("");
+ });
+}
+
+/**
+ * Insert new table data into the appropriate div on the page
+ * @param data HTML to insert at the report_table dive on the page
+ */
+function show_table_data(data) {
+ var report_table = $('#report_table');
+ report_table.html(data);
+ prettyPrint();
+}
+
+
+
+$(document).ready( function () {
+ // Setup the search widget stuff!
+ $("#dimension-ts_min_start").datetimepicker({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' });
+ $("#dimension-ts_min_end").datetimepicker({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' });
+ $('.combobox').combobox();
+ prettyPrint();
+
+ // div to insert the flot graph in
+ var theplot = $("#theplot");
+
+ // initialize the empty flot graph
+ var plot_obj = $.plot(theplot, DATA, FLOT_OPTS);
+
+ // Store references to the initial start/end times for graph resets.
+ var initial_start_time = $('#dimension-ts_min_start').val();
+ var initial_end_time = $('#dimension-ts_min_end').val();
+
+ // URL to get data for the table using the base time values on the page. This is also used to 'reset' the table.
+ var url_start_end_params = '&' + escape(TABLE_URL_TIME_START_PARAM) + '=' + escape(initial_start_time) + '&' + escape(TABLE_URL_TIME_END_PARAM) + '=' + escape(initial_end_time);
+ var table_url_now = TABLE_BASE_URL + url_start_end_params;
+
+ // Set the permlink button to have a link to the initial graph plot.
+ $('#permalink_btn').attr('href', GRAPH_PERMALINK_URL + url_start_end_params);
+
+ // If the clear button is hit, reset the plot with the new values
+ $("#reset_selection").click(function () {
+ plot_obj = $.plot($("#theplot"), DATA, FLOT_OPTS);
+ plot_obj.clearSelection();
+
+ $('#report_table').html('<center><img src="img/ajax-loader.gif"></center>');
+ $.ajax({
+ url: table_url_now,
+ method: 'GET',
+ dataType: 'html',
+ success: show_table_data
+ });
+ $("#selection").text('');
+ $('#dimension-ts_min_start').val(initial_start_time);
+ $('#dimension-ts_min_end').val(initial_end_time);
+ $('#permalink_btn').attr('href', GRAPH_PERMALINK_URL + url_start_end_params);
+ });
+
+ // kick off the initial AJAX call to get the data to plot for the graph
+ $.ajax({
+ url: GRAPH_DATA_URL + url_start_end_params,
+ method: 'GET',
+ dataType: 'json',
+ success: new_plot_data
+ });
+
+ // kick off the initial AJAX call to get the data for the table below the graph
+ $.ajax({
+ url: table_url_now,
+ method: 'GET',
+ dataType: 'html',
+ success: show_table_data
+ })
+});
+</script>
View
10 views/graph_search.php
@@ -6,15 +6,15 @@
<div class="span3">
From<br>
<div class="input-append">
- <input type="text" class="span2" name="dimension-ts_min_start" id="dimension-ts_min_start" value="<?php echo get_var('dimension-ts_min_start'); ?>">
+ <input type="text" class="span2" name="dimension-<?php echo $time_field_name ?>_start" id="dimension-ts_min_start" value="<?php echo get_var("dimension-{$time_field_name}_start"); ?>">
<span class="add-on"><i class="icon-calendar" id="dp"></i></span>
</div>
</div>
<div class="span4">
To<br>
<div class="input-append">
- <input type="text" class="span2" name="dimension-ts_min_end" id="dimension-ts_min_end" value="<?php echo get_var('dimension-ts_min_end'); ?>">
+ <input type="text" class="span2" name="dimension-<?php echo $time_field_name ?>_end" id="dimension-ts_min_end" value="<?php echo get_var("dimension-{$time_field_name}_end"); ?>">
<span class="add-on"><i class="icon-calendar" id="dp"></i></span>
</div>
</div>
@@ -41,16 +41,16 @@
<div class="row">
<div class="span3" >
Filter By Host<br>
- <select name="dimension-hostname_max" class="span3 combobox">
+ <select name="dimension-<?php echo $hostname_field_name ?>" class="span3 combobox">
<option value=""></option>
<?php foreach ($hosts as $h) { ?>
- <option value="<?php echo $h ?>" <?php if (isset($hostname_max) AND $hostname_max == $h ) { echo "SELECTED"; } ?>><?php echo $h ?></option>
+ <option value="<?php echo $h ?>" <?php if (get_var("dimension-{$hostname_field_name}")!=null AND get_var("dimension-{$hostname_field_name}") == $h ) { echo "SELECTED"; } ?>><?php echo $h ?></option>
<?php } ?>
</select>
</div>
<div class="span4" >
- <input type="checkbox" name="dimension-pivot-hostname_max" value='ts_cnt'<?php echo (isset($dimension_pivot_hostname_max) ? ' CHECKED ' : '') ?>> Show each host as a separate series
+ <input type="checkbox" name="<?php echo "dimension-pivot-{$hostname_field_name}" ?>" value='<?php echo $time_field_name ?>'<?php echo (isset($dimension_pivot_hostname_max) ? ' CHECKED ' : '') ?>> Show each host as a separate series
</div>
View
25 views/navbar.php
@@ -32,21 +32,20 @@ class="dropdown-toggle"
<?php if (isset($datasource)) { ?>
<li><a href="<?php echo site_url(). "?action=report&datasource={$datasource}"; ?>"><?php echo $datasource ?></a></li>
<li class="divider-vertical"></li>
-
- <li><a href="<?php echo site_url().'?action=graph_search&datasource='.$datasource; ?>"><i class="icon-picture icon-white" style="width: 32px"></i> Graph Search</a></li>
- <li><a href="<?php echo site_url().'?action=report&datasource='.$datasource; ?>"><i class="icon-list-alt icon-white" style="width: 16px"></i> Table Search</a></li>
+ <?php if ($source_type != 'performance_schema') { ?>
+ <li><a href="<?php echo site_url().'?action=graph_search&datasource='.$datasource; ?>"><i class="icon-picture icon-white" style="width: 32px"></i> Graph Search</a></li>
+ <li><a href="<?php echo site_url().'?action=report&datasource='.$datasource; ?>"><i class="icon-list-alt icon-white" style="width: 16px"></i> Table Search</a></li>
+ <?php } ?>
<?php } ?>
-
-
-
</ul>
- </div><!--/.nav-collapse -->
- <?php if (isset($datasource)) { ?>
- <form class="form-search form-inline pull-right" id="quicksearch" action="<?php echo site_url()."?action=quicksearch&datasource={$datasource}"; ?>" method="post">
- <input type="text" class="input-medium" name="checksum" placeholder="checksum">
- <a class="btn" href="javascript:document.getElementById('quicksearch').submit()"><i class="icon-search"></i> Find Query</a>
- </form>
- <?php } ?>
+ </div><!--/.nav-collapse -->
+ <?php if (isset($datasource) and $source_type != 'performance_schema') { ?>
+ <form class="form-search form-inline pull-right" id="quicksearch" action="<?php echo site_url()."?action=quicksearch&datasource={$datasource}"; ?>" method="post">
+ <input type="text" class="input-medium" name="checksum" placeholder="checksum">
+ <a class="btn" href="javascript:document.getElementById('quicksearch').submit()"><i class="icon-search"></i> Find Query</a>
+ </form>
+ <?php } ?>
+
</div>
</div>
</div>
View
71 views/report-performance_schema.php
@@ -0,0 +1,71 @@
+<script>
+ $(function() {
+ dbFields = [ <?php echo "'".join("','", $table_fields) ."'" ?> ];
+ $("#dimension-ts_min_start").datetimepicker({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' });
+ $("#dimension-ts_min_end").datetimepicker({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' });
+ $("#fact-first_seen").datetimepicker({ dateFormat: 'yy-mm-dd', timeFormat: 'hh:mm:ss' });
+ $(".typeahead").typeahead({ source: dbFields, items: 8});
+ $('.combobox').combobox();
+ prettyPrint();
+ });
+</script>
+
+<div class="row">
+ <form action="<?php echo site_url()."?action=report"; ?>" method="GET" class="form-inline">
+ <input type="hidden" name="action" value="report">
+ <input type="hidden" name="datasource" value="<?php echo $datasource; ?>">
+
+<div class="row">
+ <div class="span3">
+ Table Fields<br>
+ <select name="table_fields[]" class="span3" size="20" multiple="true">
+ <optgroup label="Custom Fields">
+ <?php foreach ($custom_fields as $f) { ?>
+ <option value="<?php echo $f ?>" <?php if (isset($table_fields_selected) and in_array($f, $table_fields_selected )) { echo "SELECTED"; } ?>><?php echo $f ?></option>
+ <?php } ?>
+ </optgroup>
+
+ <?php foreach (array_keys($table_fields) as $table) { ?>
+ <optgroup label="<?php echo $table; ?>">
+ <?php foreach ($table_fields[$table] as $f) { ?>
+ <option value="<?php echo $f ?>" <?php if (isset($table_fields_selected) and in_array($f, $table_fields_selected )) { echo "SELECTED"; } ?>><?php echo $f ?></option>
+ <?php } ?>
+ </optgroup>
+ <?php } ?>
+ </select>
+ </div>
+
+
+ <div class="span4">
+ Group By<br>
+ <input name="fact-group" class="span4 typeahead" value="<?php echo get_var('fact-group') ?>" data-provide="typeahead"><br><br>
+ Order By<br>
+ <input name="fact-order" class="span4 typeahead" value="<?php echo get_var('fact-order') ?>"><br><br>
+ Having<br>
+ <input name="fact-having" class="span4 typeahead" value="<?php echo get_var('fact-having') ?>"><br><br>
+ Limit<br>
+ <input name="fact-limit" class="span1" value="<?php echo get_var('fact-limit') ?>"><br><br>
+ <center>
+ <input type="submit" class="btn-primary btn-large" name="submit" value="Search">
+ </center>
+
+ </div>
+
+ <div class="span4">
+ <!--
+ Extra Fields<br>
+ <textarea name="extra_fields" class="span4" rows="6"><?php echo get_var('extra_fields') ?></textarea><br><br>
+ -->
+
+ Where<br>
+ <textarea name="fact-where" class="span4" rows="6"><?php echo get_var('fact-where') ?></textarea><br><br>
+ Query Sample Contains<br>
+ <input name="fact-DIGEST_TEXT" class="span4" value="<?php echo get_var('fact-DIGEST_TEXT') ?>"><br><br>
+
+ Digest<br>
+ <input name="fact-DIGEST" class="span4" value="<?php echo get_var('fact-DIGEST') ?>"><br><br>
+
+ </div>
+
+</div>
+<hr>
View
12 views/report.php
@@ -18,7 +18,7 @@
<div class="span3">
From<br>
<div class="input-append">
- <input type="text" class="span2" name="dimension-ts_min_start" id="dimension-ts_min_start" value="<?php echo get_var('dimension-ts_min_start'); ?>">
+ <input type="text" class="span2" name="dimension-<?php echo $time_field_name ?>_start" id="dimension-ts_min_start" value="<?php echo get_var('dimension-'.$time_field_name.'_start'); ?>">
<span class="add-on"><i class="icon-calendar" id="dp"></i></span>
</div>
</div>
@@ -28,7 +28,7 @@
<div class="span4">
To<br>
<div class="input-append">
- <input type="text" class="span2" name="dimension-ts_min_end" id="dimension-ts_min_end" value="<?php echo get_var('dimension-ts_min_end'); ?>">
+ <input type="text" class="span2" name="dimension-<?php echo $time_field_name ?>_end" id="dimension-ts_min_end" value="<?php echo get_var('dimension-'.$time_field_name.'_end'); ?>">
<span class="add-on"><i class="icon-calendar" id="dp"></i></span>
</div>
</div>
@@ -65,10 +65,10 @@
<div class="span4">
Filter By Host<br>
- <select name="dimension-hostname_max" class="span3 combobox">
+ <select name="dimension-<?php echo $host_field_name; ?>" class="span3 combobox">
<option value=""></option>
<?php foreach ($hosts as $h) { ?>
- <option value="<?php echo $h ?>" <?php if (isset($hostname_max) AND $hostname_max == $h ) { echo "SELECTED"; } ?>><?php echo $h ?></option>
+ <option value="<?php echo $h ?>" <?php if (get_var('dimension-'.$hostname_field_name) == $h ) { echo "SELECTED"; } ?>><?php echo $h ?></option>
<?php } ?>
</select><br>
@@ -95,7 +95,7 @@
Where<br>
<textarea name="fact-where" class="span4" rows="6"><?php echo get_var('fact-where') ?></textarea><br><br>
Query Sample Contains<br>
- <input name="fact-sample" class="span4" value="<?php echo get_var('fact-sample') ?>"><br><br>
+ <input name="fact-<?php echo $sample_field_name ?>" class="span4" value="<?php echo get_var('fact-'.$sample_field_name) ?>"><br><br>
Reviewed Status<br>
<select class="span4 combobox" name="fact-reviewed_status">
<option value=""></option>
@@ -105,7 +105,7 @@
</select><br>
Checksum<br>
- <input name="fact-checksum" class="span4 typeahead" value="<?php echo get_var('fact-checksum') ?>"><br><br>
+ <input name="fact-<?php echo $checksum_field_name ?>" class="span4 typeahead" value="<?php echo get_var('fact-'.$checksum_field_name) ?>"><br><br>
</div>
View
4 views/report_result.php
@@ -43,7 +43,9 @@
<?php foreach ($columns as $c ) { ?>
<?php if ($c == 'checksum') { ?>
<td><a href="<?php echo site_url()."?action=show_query&datasource={$datasource}&checksum=".$row[$c]; ?>"><?php echo $row[$c]; ?></a></td>
- <?php } else { ?>
+ <?php } else if ($c == 'DIGEST') { ?>
+ <td><a href="<?php echo site_url()."?action=show_query&datasource={$datasource}&checksum=".$row[$c]; ?>"><?php echo $row[$c]; ?></a></td>
+ <?php } else { ?>
<td><?php echo $row[$c]; ?></td>
<?php } ?>
<?php } ?>
View
8 views/show_query.php
@@ -104,10 +104,12 @@ function setupSelection(theplot) {
<div class="row">
<div class="span12">
<!-- <div class="alert alert-info"> -->
+ <?php if ($show_samples) { ?>
+
<table width="100%">
<tr>
<td>
- <strong>Last Sample</strong> on host <strong><?php echo $sample['hostname_max']; ?></strong> at <strong><?php echo $sample['ts_max']; ?></strong>
+ <strong>Last Sample</strong> on host <strong><?php echo $sample[$hostname_field_name]; ?></strong> at <strong><?php echo $sample[$time_field_name]; ?></strong>
</td>
<td>
<!-- dropdown button for more samples with counts -->
@@ -125,7 +127,9 @@ function setupSelection(theplot) {
</td>
</tr>
</table>
- <pre class="prettyprint lang-sql"><?php echo $sample['sample']; ?></pre>
+ <pre class="prettyprint lang-sql"><?php echo $sample[$sample_field_name]; ?></pre>
+ <?php } ?>
+
<?php if (isset($explain_plan_error)) { ?>
<div class="alert"><strong>Error in Query Explain Plugin:</strong> <?php echo $explain_plan_error; ?></div>
<?php } ?>

0 comments on commit bf1df55

Please sign in to comment.
Something went wrong with that request. Please try again.