├── conf └── index.html ├── views ├── index.html ├── footer.php ├── report_printr.php ├── report_json.php ├── index.php ├── noconfig.php ├── report_json2.php ├── samples.php ├── report_result.php ├── navbar.php ├── header.php ├── report-performance_schema.php ├── show_query_perf_schema.php └── report.php ├── .gitignore ├── README.md ├── img ├── box.png ├── clouds.png ├── favicon.ico ├── ane_spash.png ├── anemometer.png ├── ajax-loader.gif ├── glyphicons-halflings.png └── glyphicons-halflings-white.png ├── scripts ├── anemometer-server.cnf ├── anemometer-localhost.cnf └── anemometer_collect.sh ├── css ├── images │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_2e83ff_256x240.png │ ├── ui-icons_454545_256x240.png │ ├── ui-icons_888888_256x240.png │ ├── ui-icons_cd0a0a_256x240.png │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ ├── ui-bg_flat_75_ffffff_40x100.png │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_glass_75_dadada_1x400.png │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ ├── ui-bg_glass_95_fef1ec_1x400.png │ └── ui-bg_highlight-soft_75_cccccc_1x100.png ├── prettify.css └── bootstrap-combobox.css ├── docs ├── blank.html ├── media │ └── banner.css ├── classtrees_Loader.html ├── classtrees_Anemometer.html ├── classtrees_QueryExplain.html ├── classtrees_AnemometerModel.html ├── classtrees_MySQLTableReport.html ├── classtrees_QueryTableParser.html ├── packages.html ├── index.html ├── li_Loader.html ├── li_Anemometer.html ├── li_QueryExplain.html ├── li_AnemometerModel.html ├── li_MySQLTableReport.html ├── li_QueryTableParser.html ├── classtrees_default.html ├── Loader │ ├── _Loader.php.html │ └── Loader.html ├── default │ ├── _Loader.php.html │ ├── _QueryTableParser.php.html │ ├── _MySQLTableReport.php.html │ ├── _AnemometerModel.php.html │ ├── _Anemometer.php.html │ ├── _QueryExplain.php.html │ ├── Loader.html │ └── _Helpers.php.html ├── QueryTableParser │ └── _QueryTableParser.php.html ├── MySQLTableReport │ └── _MySQLTableReport.php.html ├── AnemometerModel │ └── _AnemometerModel.php.html ├── li_default.html ├── elementindex_Loader.html ├── QueryExplain │ └── _QueryExplain.php.html ├── errors.html ├── Anemometer │ └── _Anemometer.php.html └── elementindex_QueryTableParser.html ├── js ├── flot │ ├── jquery.flot.symbol.min.js │ ├── jquery.flot.threshold.min.js │ ├── jquery.flot.resize.min.js │ ├── jquery.flot.stack.min.js │ ├── jquery.flot.fillbetween.min.js │ ├── jquery.flot.crosshair.min.js │ ├── jquery.flot.image.min.js │ ├── jquery.flot.resize.js │ ├── jquery.flot.symbol.js │ ├── jquery.colorhelpers.min.js │ ├── jquery.flot.selection.min.js │ ├── jquery.flot.threshold.js │ ├── jquery.flot.navigate.min.js │ └── jquery.flot.crosshair.js ├── bootstrap-dropdown.js ├── lang-sql.js ├── bootstrap-tab.js ├── bootstrap-collapse.js └── bootstrap-combobox.js ├── mysql56-save_history.sql ├── audit_sql_day.py ├── index.php ├── vagrant ├── bootstrap.sh └── Vagrantfile ├── lib ├── Loader.php ├── Helpers.php ├── QueryTableParser.php └── QueryRewrite.php ├── audit_sql.py ├── mysql56-install.sql ├── CONTRIBUTING.md └── install.sql /conf/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | conf/config.inc.php 2 | *.komodoproject 3 | -------------------------------------------------------------------------------- /views/footer.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # anemometerAudit_SQL 2 | Box anemometer add audit sql function. 3 | -------------------------------------------------------------------------------- /img/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/box.png -------------------------------------------------------------------------------- /img/clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/clouds.png -------------------------------------------------------------------------------- /img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/favicon.ico -------------------------------------------------------------------------------- /scripts/anemometer-server.cnf: -------------------------------------------------------------------------------- 1 | [client] 2 | user=anemometer 3 | password=anemometerpass 4 | -------------------------------------------------------------------------------- /views/report_printr.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/ane_spash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/ane_spash.png -------------------------------------------------------------------------------- /img/anemometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/anemometer.png -------------------------------------------------------------------------------- /img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/ajax-loader.gif -------------------------------------------------------------------------------- /img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /scripts/anemometer-localhost.cnf: -------------------------------------------------------------------------------- 1 | [client] 2 | user=anemometer 3 | password=anemometerpass 4 | host=192.168.1.1 5 | -------------------------------------------------------------------------------- /views/report_json.php: -------------------------------------------------------------------------------- 1 | $columns, 'result' => $result )); 4 | 5 | ?> -------------------------------------------------------------------------------- /img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /css/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /css/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ISADBA/anemometerAudit_SQL/HEAD/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /docs/blank.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Generated Documentation 4 | 5 | 6 | 7 | 8 |

Generated Documentation

9 | Welcome to default!
10 |
11 | This documentation was generated by phpDocumentor v1.4.4
12 | 13 | -------------------------------------------------------------------------------- /docs/media/banner.css: -------------------------------------------------------------------------------- 1 | body 2 | { 3 | background-color: #CCCCFF; 4 | margin: 0px; 5 | padding: 0px; 6 | } 7 | 8 | /* Banner (top bar) classes */ 9 | 10 | .banner { } 11 | 12 | .banner-menu 13 | { 14 | clear: both; 15 | padding: .5em; 16 | border-top: 2px solid #6666AA; 17 | } 18 | 19 | .banner-title 20 | { 21 | text-align: right; 22 | font-size: 20pt; 23 | font-weight: bold; 24 | margin: .2em; 25 | } 26 | 27 | .package-selector 28 | { 29 | background-color: #AAAADD; 30 | border: 1px solid black; 31 | color: yellow; 32 | } 33 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.symbol.min.js: -------------------------------------------------------------------------------- 1 | (function(b){function a(h,e,g){var d={square:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.rect(j-l,n-l,l+l,l+l)},diamond:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI/2);k.moveTo(j-l,n);k.lineTo(j,n-l);k.lineTo(j+l,n);k.lineTo(j,n+l);k.lineTo(j-l,n)},triangle:function(l,k,o,j,n){var m=j*Math.sqrt(2*Math.PI/Math.sin(Math.PI/3));var i=m*Math.sin(Math.PI/3);l.moveTo(k-m/2,o+i/2);l.lineTo(k+m/2,o+i/2);if(!n){l.lineTo(k,o-i/2);l.lineTo(k-m/2,o+i/2)}},cross:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.moveTo(j-l,n-l);k.lineTo(j+l,n+l);k.moveTo(j-l,n+l);k.lineTo(j+l,n-l)}};var f=e.points.symbol;if(d[f]){e.points.symbol=d[f]}}function c(d){d.hooks.processDatapoints.push(a)}b.plot.plugins.push({init:c,name:"symbols",version:"1.0"})})(jQuery); -------------------------------------------------------------------------------- /docs/classtrees_Loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class Loader

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /docs/classtrees_Anemometer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class Anemometer

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /docs/classtrees_QueryExplain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class QueryExplain

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.threshold.min.js: -------------------------------------------------------------------------------- 1 | (function(B){var A={series:{threshold:null}};function C(D){function E(L,S,M){if(!S.threshold){return }var F=M.pointsize,I,O,N,G,K,H=B.extend({},S);H.datapoints={points:[],pointsize:F};H.label=null;H.color=S.threshold.color;H.threshold=null;H.originSeries=S;H.data=[];var P=S.threshold.below,Q=M.points,R=S.lines.show;threspoints=[];newpoints=[];for(I=0;I0&&Q[I-F]!=null){var J=(O-Q[I-F])/(N-Q[I-F+1])*(P-N)+O;K.push(J);K.push(P);for(m=2;m0){L.getData().push(H)}}D.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"threshold",version:"1.0"})})(jQuery); -------------------------------------------------------------------------------- /docs/classtrees_AnemometerModel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class AnemometerModel

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /docs/classtrees_MySQLTableReport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class MySQLTableReport

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /docs/classtrees_QueryTableParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class QueryTableParser

17 | 19 | 20 |

21 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 22 |

23 | 24 | -------------------------------------------------------------------------------- /views/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 |

Choose a Datasource

8 | 9 |
" method="post"> 10 |
11 | 12 |
13 | 18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
-------------------------------------------------------------------------------- /docs/packages.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 26 | 27 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | Generated Documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | <H2>Frame Alert</H2> 20 | <P>This document is designed to be viewed using the frames feature. 21 | If you see this message, you are using a non-frame-capable web client.</P> 22 | 23 | 24 | -------------------------------------------------------------------------------- /mysql56-save_history.sql: -------------------------------------------------------------------------------- 1 | USE slow_query_log; 2 | 3 | CREATE TEMPORARY TABLE `statements_temp` SELECT * FROM performance_schema.events_statements_summary_by_digest; 4 | 5 | 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); 6 | 7 | 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'; 8 | PREPARE stmt FROM @stmt; 9 | EXECUTE stmt; 10 | 11 | DROP TABLE IF EXISTS statements_temp; 12 | TRUNCATE TABLE performance_schema.events_statements_summary_by_digest; 13 | -------------------------------------------------------------------------------- /audit_sql_day.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | '''auto audit sql task 3 | ''' 4 | import MySQLdb 5 | db = MySQLdb.connect("192.168.11.28","anemometer","anemometerpass","slow_query_log_192_168_11_17") 6 | 7 | def run(): 8 | cursor = db.cursor() 9 | sql = '''UPDATE `global_query_review` aa,( 10 | SELECT 11 | a.`checksum`, 12 | COUNT(b.`checksum`) AS coun 13 | FROM 14 | `global_query_review` a, 15 | global_query_review_history b 16 | WHERE a.`checksum` = b.`checksum` 17 | AND a.audit_status = 'refuse' 18 | GROUP BY a.`checksum` 19 | HAVING MAX(b.`Query_time_max`) < %s 20 | AND AVG(b.`Lock_time_max`) < %s 21 | AND (MAX(b.`Rows_sent_max`) <= 1000) 22 | AND MAX(b.`Rows_examined_max`) < 5000 23 | AND AVG(b.`Bytes_median`) < 5000 24 | AND coun < 5 25 | ) bb 26 | SET aa.`audit_status` = 'pass' 27 | WHERE aa.`checksum` = bb.checksum 28 | ''' % (1,0.01) 29 | cursor.execute(sql) 30 | try: 31 | cursor.execute(sql) 32 | db.commit() 33 | print 'Exec sucessful' 34 | except: 35 | db.rollback() 36 | print 'Exec fail' 37 | db.close() 38 | 39 | if __name__=='__main__': 40 | run() 41 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.resize.min.js: -------------------------------------------------------------------------------- 1 | (function(n,p,u){var w=n([]),s=n.resize=n.extend(n.resize,{}),o,l="setTimeout",m="resize",t=m+"-special-event",v="delay",r="throttleWindow";s[v]=250;s[r]=true;n.event.special[m]={setup:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.add(a);n.data(this,t,{w:a.width(),h:a.height()});if(w.length===1){q()}},teardown:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.not(a);a.removeData(t);if(!w.length){clearTimeout(o)}},add:function(b){if(!s[r]&&this[l]){return false}var c;function a(d,h,g){var f=n(this),e=n.data(this,t);e.w=h!==u?h:f.width();e.h=g!==u?g:f.height();c.apply(this,arguments)}if(n.isFunction(b)){c=b;return a}else{c=b.handler;b.handler=a}}};function q(){o=p[l](function(){w.each(function(){var d=n(this),a=d.width(),b=d.height(),c=n.data(this,t);if(a!==c.w||b!==c.h){d.trigger(m,[c.w=a,c.h=b])}});q()},s[v])}})(jQuery,this);(function(b){var a={};function c(f){function e(){var h=f.getPlaceholder();if(h.width()==0||h.height()==0){return}f.resize();f.setupGrid();f.draw()}function g(i,h){i.getPlaceholder().resize(e)}function d(i,h){i.getPlaceholder().unbind("resize",e)}f.hooks.bindEvents.push(g);f.hooks.shutdown.push(d)}b.plot.plugins.push({init:c,options:a,name:"resize",version:"1.0"})})(jQuery); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | , Geoffrey Anderson 7 | * @created 2012-01-01 8 | * @license Apache 2.0 license. See LICENSE document for more info 9 | **/ 10 | 11 | // Ensure we're on php 5.3 or newer 12 | if (strnatcmp(phpversion(), '5.3') < 0) { 13 | print "Anemometer requires PHP 5.3 or newer. You have ".phpversion(); 14 | die(); 15 | } 16 | 17 | if (!function_exists('bcadd')) { 18 | print "Anemometer requires the BCMath extension"; 19 | die(); 20 | } 21 | 22 | set_include_path( get_include_path() . PATH_SEPARATOR . "./lib"); 23 | require "Helpers.php"; 24 | require "Anemometer.php"; 25 | 26 | error_reporting(E_ALL); 27 | $action = isset($_GET['action']) ? $_GET['action'] : 'index'; 28 | 29 | $conf = array(); 30 | @include "conf/config.inc.php"; 31 | if (empty($conf)) 32 | { 33 | $action = 'noconfig'; 34 | } 35 | 36 | $controller = new Anemometer($conf); 37 | if (is_callable(array($controller, $action ))) 38 | { 39 | $controller->$action(); 40 | } 41 | else 42 | { 43 | print "Invalid action ($action)"; 44 | } 45 | 46 | ?> 47 | -------------------------------------------------------------------------------- /views/noconfig.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
    7 |
  • 8 |
  • 9 |
  • 10 |
11 |
12 | 13 |
14 |
15 |

SQL Anemometer

16 |


17 |

You're seeing this page because you haven't configured Anemometer yet.

18 |


19 |

Please find the sample config file at conf/sample.config.inc.php, rename it to conf/config.inc.php and follow its instructions to set up your enviroment

20 |


21 |

Github Project Page / Documentation

22 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.stack.min.js: -------------------------------------------------------------------------------- 1 | (function(b){var a={series:{stack:null}};function c(f){function d(k,j){var h=null;for(var g=0;g2&&(G?g.format[2].x:g.format[2].y),n=u&&v.lines.steps,E=true,q=G?1:0,H=G?0:1,D=0,B=0,A;while(true){if(D>=F.length){break}A=t.length;if(F[D]==null){for(m=0;m=y.length){if(!u){for(m=0;mJ){if(u&&D>0&&F[D-z]!=null){k=w+(F[D-z+H]-w)*(J-x)/(F[D-z+q]-x);t.push(J);t.push(k+I);for(m=2;m0&&y[B-h]!=null){r=I+(y[B-h+H]-I)*(x-J)/(y[B-h+q]-J)}t[A+H]+=r;D+=z}}E=false;if(A!=t.length&&o){t[A+2]+=r}}}}if(n&&A!=t.length&&A>0&&t[A]!=null&&t[A]!=t[A-z]&&t[A+1]!=t[A-z+1]){for(m=0;m=h.length){return null}return h[g]}return null}function e(B,u,g){if(u.fillBetween==null){return}var p=d(u,B.getData());if(!p){return}var y=g.pointsize,E=g.points,h=p.datapoints.pointsize,x=p.datapoints.points,r=[],w,v,k,G,F,q,t=u.lines.show,o=y>2&&g.format[2].y,n=t&&u.lines.steps,D=true,C=0,A=0,z;while(true){if(C>=E.length){break}z=r.length;if(E[C]==null){for(m=0;m=x.length){if(!t){for(m=0;mG){if(t&&C>0&&E[C-y]!=null){k=v+(E[C-y+1]-v)*(G-w)/(E[C-y]-w);r.push(G);r.push(k);for(m=2;m0&&x[A-h]!=null){q=F+(x[A-h+1]-F)*(w-G)/(x[A-h]-G)}C+=y}}D=false;if(z!=r.length&&o){r[z+2]=q}}}}if(n&&z!=r.length&&z>0&&r[z]!=null&&r[z]!=r[z-y]&&r[z+1]!=r[z-y+1]){for(m=0;m 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
Loader
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
Loader
26 |
Files
27 |
Loader.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /docs/li_Anemometer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
Anemometer
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
Anemometer
26 |
Files
27 |
Anemometer.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.crosshair.min.js: -------------------------------------------------------------------------------- 1 | (function(b){var a={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};function c(h){var j={x:-1,y:-1,locked:false};h.setCrosshair=function e(l){if(!l){j.x=-1}else{var k=h.p2c(l);j.x=Math.max(0,Math.min(k.left,h.width()));j.y=Math.max(0,Math.min(k.top,h.height()))}h.triggerRedrawOverlay()};h.clearCrosshair=h.setCrosshair;h.lockCrosshair=function f(k){if(k){h.setCrosshair(k)}j.locked=true};h.unlockCrosshair=function g(){j.locked=false};function d(k){if(j.locked){return}if(j.x!=-1){j.x=-1;h.triggerRedrawOverlay()}}function i(k){if(j.locked){return}if(h.getSelection&&h.getSelection()){j.x=-1;return}var l=h.offset();j.x=Math.max(0,Math.min(k.pageX-l.left,h.width()));j.y=Math.max(0,Math.min(k.pageY-l.top,h.height()));h.triggerRedrawOverlay()}h.hooks.bindEvents.push(function(l,k){if(!l.getOptions().crosshair.mode){return}k.mouseout(d);k.mousemove(i)});h.hooks.drawOverlay.push(function(m,k){var n=m.getOptions().crosshair;if(!n.mode){return}var l=m.getPlotOffset();k.save();k.translate(l.left,l.top);if(j.x!=-1){k.strokeStyle=n.color;k.lineWidth=n.lineWidth;k.lineJoin="round";k.beginPath();if(n.mode.indexOf("x")!=-1){k.moveTo(j.x,0);k.lineTo(j.x,m.height())}if(n.mode.indexOf("y")!=-1){k.moveTo(0,j.y);k.lineTo(m.width(),j.y)}k.stroke()}k.restore()});h.hooks.shutdown.push(function(l,k){k.unbind("mouseout",d);k.unbind("mousemove",i)})}b.plot.plugins.push({init:c,options:a,name:"crosshair",version:"1.0"})})(jQuery); -------------------------------------------------------------------------------- /vagrant/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # base packages, including percona mysql repo 4 | yum install -y http://www.percona.com/downloads/percona-release/percona-release-0.0-1.x86_64.rpm 5 | yum install -y Percona-Server-client-56 Percona-Server-shared-56 Percona-Server-server-56 6 | yum install -y httpd php php-mysql php-bcmath 7 | 8 | # add init scripts & auto start 9 | chkconfig --levels 235 mysqld on 10 | /etc/init.d/mysql start 11 | chkconfig --levels 235 httpd on 12 | /etc/init.d/httpd start 13 | 14 | # setup symlink for apache & install anemometer files 15 | ln -s /vagrant/anemometer /var/www/html/anemometer 16 | mysql -u root < /vagrant/anemometer/install.sql 17 | mysql -u root < /vagrant/anemometer/mysql56-install.sql 18 | 19 | # install percona toolkit 20 | yum install -y perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL 21 | wget -q "http://www.percona.com/redir/downloads/percona-toolkit/2.2.10/RPM/percona-toolkit-2.2.10-1.noarch.rpm" 22 | rpm -i percona-toolkit-2.2.10-1.noarch.rpm 23 | 24 | # create my.cnf for access 25 | cat << EOF > /home/vagrant/.my.cnf 26 | [client] 27 | user=root 28 | EOF 29 | 30 | # add cron for collection script 31 | cat << EOF > /home/vagrant/crontab 32 | */5 * * * * /vagrant/anemometer/scripts/anemometer_collect.sh --interval 15 --history-db-host localhost --defaults-file /home/vagrant/.my.cnf --history-defaults-file /home/vagrant/.my.cnf 33 | EOF 34 | crontab -u root /home/vagrant/crontab 35 | -------------------------------------------------------------------------------- /docs/li_QueryExplain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
QueryExplain
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
QueryExplain
26 |
Files
27 |
QueryExplain.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /docs/li_AnemometerModel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
AnemometerModel
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
AnemometerModel
26 |
Files
27 |
AnemometerModel.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /docs/li_MySQLTableReport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
MySQLTableReport
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
MySQLTableReport
26 |
Files
27 |
MySQLTableReport.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /docs/li_QueryTableParser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
QueryTableParser
12 |
13 | 14 |
15 | 16 |
Description
17 |
18 | Class trees
19 | Index of elements
20 |
21 | 22 | 23 | 24 |
Classes
25 |
QueryTableParser
26 |
Files
27 |
QueryTableParser.php
28 | 29 | 30 |
31 |
32 |

phpDocumentor v 1.4.4

33 | 34 | -------------------------------------------------------------------------------- /docs/classtrees_default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

16 |

Root class Anemometer

17 | 19 | 20 |

Root class AnemometerModel

21 | 23 | 24 |

Root class Loader

25 | 27 | 28 |

Root class MySQLTableReport

29 | 31 | 32 |

Root class QueryExplain

33 | 35 | 36 |

Root class QueryTableParser

37 | 39 | 40 |

41 | Documentation generated on Mon, 12 Mar 2012 11:59:40 -0700 by phpDocumentor 1.4.4 42 |

43 | 44 | -------------------------------------------------------------------------------- /views/report_json2.php: -------------------------------------------------------------------------------- 1 | ".$sql.""; 8 | } 9 | 10 | $series = array_filter($columns, function ($x) use ($group) { return $x == $group ? false : true; }); 11 | $wtfdata = array(); 12 | if (count($result)) 13 | { 14 | if (preg_match("/^\d+$/", $result[0][$group])) 15 | { 16 | $is_datetime = false; 17 | } 18 | else 19 | { 20 | $is_datetime = true; 21 | } 22 | } 23 | foreach ($result as $row) 24 | { 25 | foreach ($series as $col) 26 | { 27 | $date = $row[$group]; 28 | if ($is_datetime) 29 | { 30 | $parts = strptime($date, "%Y-%m-%d %H:%M:%S"); 31 | $date = mktime($parts['tm_hour'], $parts['tm_min'],$parts['tm_sec'], $parts['tm_mon']+1, $parts['tm_mday'], $parts['tm_year']+1900); 32 | } 33 | $wtfdata[$col][] = array( $date, $row[$col]); 34 | } 35 | } 36 | 37 | foreach ($series as $col) 38 | { 39 | // this is intended to capture checksum values when we pivot on checksums 40 | // and convert them to hex. Done here because Javascript can't handle large enough 41 | // int values to convert them w/out loss of precision. 42 | // this may have some unintended consequences, but it's the easist way to solve the JS 43 | // limitation for now 44 | $col_label = $col; 45 | if (is_numeric($col_label)) { 46 | $col_label = dec2hex($col_label); 47 | } 48 | $finalfingdata[] = array( 'label' => $col_label, 'data' => $wtfdata[$col]); 49 | } 50 | print json_encode($finalfingdata); 51 | 52 | ?> -------------------------------------------------------------------------------- /lib/Loader.php: -------------------------------------------------------------------------------- 1 | 6 | * @created 2012-01-01 7 | * @license Apache 2.0 license. See LICENSE document for more info 8 | */ 9 | class Loader 10 | { 11 | 12 | /** 13 | * Finds and displays the given view, and makes the values in $data available to it. 14 | * The name of the view is passed in without the leading "views/" directory or the trailing 15 | * ".php" extension. So loading a view with $this->view("myview"); would look for a file 16 | * called "views/myview.php" 17 | * 18 | * the data is made available my taking the keys of $data, and assigning them to 19 | * a locally scoped variable of the same name. array( 'title' => 'The Title' ) 20 | * would be available in the view as $title. 21 | * 22 | * @param string $view_name The name of the view to load 23 | * @param type $data array of values to make available to the view 24 | */ 25 | public function view($view_name, $data = null) 26 | { 27 | // make local variables out of array keys 28 | if (is_array($data)) 29 | { 30 | foreach($data as $key => $value) 31 | { 32 | ${$key} = $value; 33 | } 34 | } 35 | 36 | // find and include the view 37 | $view_name = "views/{$view_name}.php"; 38 | if (file_exists($view_name)) 39 | { 40 | include $view_name; 41 | } 42 | else 43 | { 44 | print "
Error {$view_name} not found
"; 45 | } 46 | } 47 | 48 | } 49 | 50 | ?> -------------------------------------------------------------------------------- /css/prettify.css: -------------------------------------------------------------------------------- 1 | /* Pretty printing styles. Used with prettify.js. */ 2 | 3 | /* SPAN elements with the classes below are added by prettyprint. */ 4 | .pln { color: #000 } /* plain text */ 5 | 6 | @media screen { 7 | .str { color: #080 } /* string content */ 8 | .kwd { color: #008 } /* a keyword */ 9 | .com { color: #800 } /* a comment */ 10 | .typ { color: #606 } /* a type name */ 11 | .lit { color: #066 } /* a literal value */ 12 | /* punctuation, lisp open bracket, lisp close bracket */ 13 | .pun, .opn, .clo { color: #660 } 14 | .tag { color: #008 } /* a markup tag name */ 15 | .atn { color: #606 } /* a markup attribute name */ 16 | .atv { color: #080 } /* a markup attribute value */ 17 | .dec, .var { color: #606 } /* a declaration; a variable name */ 18 | .fun { color: red } /* a function name */ 19 | } 20 | 21 | /* Use higher contrast and text-weight for printable form. */ 22 | @media print, projection { 23 | .str { color: #060 } 24 | .kwd { color: #006; font-weight: bold } 25 | .com { color: #600; font-style: italic } 26 | .typ { color: #404; font-weight: bold } 27 | .lit { color: #044 } 28 | .pun, .opn, .clo { color: #440 } 29 | .tag { color: #006; font-weight: bold } 30 | .atn { color: #404 } 31 | .atv { color: #060 } 32 | } 33 | 34 | /* Put a border around prettyprinted code snippets. */ 35 | pre.prettyprint { padding: 2px; border: 1px solid #888 } 36 | 37 | /* Specify class=linenums on a pre to get line numbering */ 38 | ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ 39 | li.L0, 40 | li.L1, 41 | li.L2, 42 | li.L3, 43 | li.L5, 44 | li.L6, 45 | li.L7, 46 | li.L8 { list-style-type: none } 47 | /* Alternate shading for lines */ 48 | li.L1, 49 | li.L3, 50 | li.L5, 51 | li.L7, 52 | li.L9 { background: #eee } 53 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.image.min.js: -------------------------------------------------------------------------------- 1 | (function(c){var a={series:{images:{show:false,alpha:1,anchor:"corner"}}};c.plot.image={};c.plot.image.loadDataImages=function(g,f,k){var j=[],h=[];var i=f.series.images.show;c.each(g,function(l,m){if(!(i||m.images.show)){return}if(m.data){m=m.data}c.each(m,function(n,o){if(typeof o[0]=="string"){j.push(o[0]);h.push(o)}})});c.plot.image.load(j,function(l){c.each(h,function(n,o){var m=o[0];if(l[m]){o[0]=l[m]}});k()})};c.plot.image.load=function(h,i){var g=h.length,f={};if(g==0){i({})}c.each(h,function(k,j){var l=function(){--g;f[j]=this;if(g==0){i(f)}};c("").load(l).error(l).attr("src",j)})};function d(q,o,l){var m=q.getPlotOffset();if(!l.images||!l.images.show){return}var r=l.datapoints.points,n=l.datapoints.pointsize;for(var t=0;tv){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}if(l.images.anchor=="center"){x=0.5*(v-w)/(y.width-1);w-=x;v+=x;x=0.5*(f-g)/(y.height-1);g-=x;f+=x}if(w==v||g==f||w>=h.max||v<=h.min||g>=u.max||f<=u.min){continue}var k=0,s=0,j=y.width,p=y.height;if(wh.max){j+=(j-k)*(h.max-v)/(v-w);v=h.max}if(gu.max){s+=(s-p)*(u.max-f)/(f-g);f=u.max}w=h.p2c(w);v=h.p2c(v);g=u.p2c(g);f=u.p2c(f);if(w>v){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}x=o.globalAlpha;o.globalAlpha*=l.images.alpha;o.drawImage(y,k,s,j-k,p-s,w+m.left,g+m.top,v-w,f-g);o.globalAlpha=x}}function b(i,f,g,h){if(!f.images.show){return}h.format=[{required:true},{x:true,number:true,required:true},{y:true,number:true,required:true},{x:true,number:true,required:true},{y:true,number:true,required:true}]}function e(f){f.hooks.processRawData.push(b);f.hooks.drawSeries.push(d)}c.plot.plugins.push({init:e,options:a,name:"image",version:"1.1"})})(jQuery); -------------------------------------------------------------------------------- /views/samples.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 9 | 10 |
11 |
12 | Displaying samples - 13 | 0) { ?> 14 | "class="btn">← Newer 15 | 16 | 17 | $limit) { ?> 18 | " class="btn">Older → 19 | 20 |
21 |
22 |
23 | 24 | fetch_assoc(); 26 | ?> 27 |
28 |
29 | Sample on host at 30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 | Displaying samples - 38 | 0) { ?> 39 | "class="btn">← Newer 40 | 41 | 42 | $limit) { ?> 43 | " class="btn">Older → 44 | 45 |
46 |
47 | 48 | 53 | -------------------------------------------------------------------------------- /audit_sql.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | '''auto audit sql task 3 | ''' 4 | import MySQLdb 5 | db = MySQLdb.connect("192.168.11.28","anemometer","anemometerpass","slow_query_log_192_168_11_17") 6 | 7 | def run(): 8 | cursor = db.cursor() 9 | sql = '''UPDATE `global_query_review` aa,( 10 | SELECT 11 | a.`checksum`, 12 | MAX(b.`Query_time_max`), 13 | AVG(b.`Query_time_pct_95`), 14 | AVG(b.`Query_time_median`), 15 | AVG(b.`Lock_time_pct_95`), 16 | MAX(b.`Rows_sent_max`), 17 | AVG(b.`Rows_sent_pct_95`), 18 | AVG(b.`Rows_examined_pct_95`), 19 | MAX(b.`Rows_examined_max`), 20 | AVG(b.`Bytes_median`) 21 | FROM 22 | `global_query_review` a, 23 | global_query_review_history b 24 | WHERE a.`checksum` = b.`checksum` 25 | and a.audit_status = 'refuse' 26 | GROUP BY a.`checksum` 27 | HAVING 28 | ( 29 | MAX(b.`Query_time_max`) < %s 30 | OR AVG(b.`Query_time_pct_95`) < %s 31 | OR AVG(b.`Query_time_median`) < %s 32 | ) 33 | AND AVG(b.`Lock_time_pct_95`) < %s 34 | AND ( 35 | MAX(b.`Rows_sent_max`) < 1000 36 | OR AVG(b.`Rows_sent_pct_95`) < 100 37 | ) 38 | AND ( 39 | AVG(b.`Rows_examined_pct_95`) < 500 40 | OR MAX(b.`Rows_examined_max`) < 2000 41 | ) 42 | AND AVG(b.`Bytes_median`) < 1000 43 | ) bb 44 | SET aa.`audit_status` = 'pass' 45 | WHERE aa.`checksum` = bb.checksum 46 | ''' % (0.1,0.08,0.06,0.01) 47 | 48 | sql2 = '''UPDATE 49 | `global_query_review` a 50 | SET 51 | a.`audit_status` = 'pass' 52 | WHERE a.`audit_status` = 'refuse' 53 | AND (a.`sample` LIKE '%show create table%' OR a.`sample` LIKE '%/*!40001 SQL_NO_CACHE */%' OR a.sample LIKE 'explain%' OR a.sample LIKE 'select * from%'); 54 | ''' 55 | try: 56 | cursor.execute(sql) 57 | cursor.execute(sql2) 58 | db.commit() 59 | print 'Exec sucessful' 60 | except: 61 | db.rollback() 62 | print 'Exec fail' 63 | 64 | db.close() 65 | 66 | if __name__=='__main__': 67 | run() 68 | -------------------------------------------------------------------------------- /docs/Loader/_Loader.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page Loader.php 7 | 8 | 9 | 10 | 11 |
12 |

/Loader.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | Loader 43 | 45 | class to mimic codigniter's syntax for loading views from the controller 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /docs/default/_Loader.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page Loader.php 7 | 8 | 9 | 10 | 11 |
12 |

/Loader.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | Loader 43 | 45 | class to mimic codigniter's syntax for loading views from the controller 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /docs/default/_QueryTableParser.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page QueryTableParser.php 7 | 8 | 9 | 10 | 11 |
12 |

/QueryTableParser.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | QueryTableParser 43 | 45 | class QueryTableParser 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /docs/QueryTableParser/_QueryTableParser.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page QueryTableParser.php 7 | 8 | 9 | 10 | 11 |
12 |

/QueryTableParser.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | QueryTableParser 43 | 45 | class QueryTableParser 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /docs/default/_MySQLTableReport.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page MySQLTableReport.php 7 | 8 | 9 | 10 | 11 |
12 |

/MySQLTableReport.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | MySQLTableReport 43 | 45 | class MySQLTableReport Generic reporting class. Given a configuration file, that describes the tables and fields to be searched, and information to connect to a database, take form data and generate an SQL query to run. 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /docs/MySQLTableReport/_MySQLTableReport.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page MySQLTableReport.php 7 | 8 | 9 | 10 | 11 |
12 |

/MySQLTableReport.php

13 | 14 | 15 |
16 |
Description
17 | 21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
Classes
30 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 47 | 48 |
ClassDescription
42 | MySQLTableReport 43 | 45 | class MySQLTableReport Generic reporting class. Given a configuration file, that describes the tables and fields to be searched, and information to connect to a database, take form data and generate an SQL query to run. 46 |
49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 |

57 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 58 |

59 |
60 | -------------------------------------------------------------------------------- /mysql56-install.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS slow_query_log; 2 | 3 | USE slow_query_log; 4 | 5 | CREATE TABLE events_statements ( 6 | `DIGEST` varchar(32) character set binary NOT NULL , 7 | `DIGEST_TEXT` longtext NOT NULL, 8 | `first_seen` datetime DEFAULT NULL, 9 | `last_seen` datetime DEFAULT NULL, 10 | `reviewed_by` varchar(20) DEFAULT NULL, 11 | `reviewed_on` datetime DEFAULT NULL, 12 | `reviewed_status` varchar(24) DEFAULT NULL, 13 | `comments` text, 14 | PRIMARY KEY (`DIGEST`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 16 | 17 | CREATE TABLE events_statements_history ( 18 | history_id bigint unsigned not null auto_increment PRIMARY KEY, 19 | hostname varchar(48) not null default '', 20 | `DIGEST` varchar(32) character set binary DEFAULT NULL , 21 | `DIGEST_TEXT` longtext, 22 | `COUNT_STAR` bigint(20) unsigned NOT NULL, 23 | `SUM_TIMER_WAIT` bigint(20) unsigned NOT NULL, 24 | `MIN_TIMER_WAIT` bigint(20) unsigned NOT NULL, 25 | `AVG_TIMER_WAIT` bigint(20) unsigned NOT NULL, 26 | `MAX_TIMER_WAIT` bigint(20) unsigned NOT NULL, 27 | `SUM_LOCK_TIME` bigint(20) unsigned NOT NULL, 28 | `SUM_ERRORS` bigint(20) unsigned NOT NULL, 29 | `SUM_WARNINGS` bigint(20) unsigned NOT NULL, 30 | `SUM_ROWS_AFFECTED` bigint(20) unsigned NOT NULL, 31 | `SUM_ROWS_SENT` bigint(20) unsigned NOT NULL, 32 | `SUM_ROWS_EXAMINED` bigint(20) unsigned NOT NULL, 33 | `SUM_CREATED_TMP_DISK_TABLES` bigint(20) unsigned NOT NULL, 34 | `SUM_CREATED_TMP_TABLES` bigint(20) unsigned NOT NULL, 35 | `SUM_SELECT_FULL_JOIN` bigint(20) unsigned NOT NULL, 36 | `SUM_SELECT_FULL_RANGE_JOIN` bigint(20) unsigned NOT NULL, 37 | `SUM_SELECT_RANGE` bigint(20) unsigned NOT NULL, 38 | `SUM_SELECT_RANGE_CHECK` bigint(20) unsigned NOT NULL, 39 | `SUM_SELECT_SCAN` bigint(20) unsigned NOT NULL, 40 | `SUM_SORT_MERGE_PASSES` bigint(20) unsigned NOT NULL, 41 | `SUM_SORT_RANGE` bigint(20) unsigned NOT NULL, 42 | `SUM_SORT_ROWS` bigint(20) unsigned NOT NULL, 43 | `SUM_SORT_SCAN` bigint(20) unsigned NOT NULL, 44 | `SUM_NO_INDEX_USED` bigint(20) unsigned NOT NULL, 45 | `SUM_NO_GOOD_INDEX_USED` bigint(20) unsigned NOT NULL, 46 | `FIRST_SEEN` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 47 | `LAST_SEEN` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 48 | UNIQUE KEY (`DIGEST`, `hostname`, FIRST_SEEN, LAST_SEEN ) 49 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 50 | -------------------------------------------------------------------------------- /views/report_result.php: -------------------------------------------------------------------------------- 1 | 13 |
14 |
15 | Show Raw SQL 16 | 20 | 21 | Permalink 22 | JSON 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 |
35 | Showing results 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | $fx) { 49 | if (array_key_exists($fxname, $row)) { 50 | $result = $fx($row[$fxname]); 51 | $row[$fxname] = $result[0]; 52 | $row_class[] = $result[1]; 53 | } 54 | } 55 | } 56 | ?> 57 | "> 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
">">
70 |
71 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.resize.js: -------------------------------------------------------------------------------- 1 | /* 2 | Flot plugin for automatically redrawing plots when the placeholder 3 | size changes, e.g. on window resizes. 4 | 5 | It works by listening for changes on the placeholder div (through the 6 | jQuery resize event plugin) - if the size changes, it will redraw the 7 | plot. 8 | 9 | There are no options. If you need to disable the plugin for some 10 | plots, you can just fix the size of their placeholders. 11 | */ 12 | 13 | 14 | /* Inline dependency: 15 | * jQuery resize event - v1.1 - 3/14/2010 16 | * http://benalman.com/projects/jquery-resize-plugin/ 17 | * 18 | * Copyright (c) 2010 "Cowboy" Ben Alman 19 | * Dual licensed under the MIT and GPL licenses. 20 | * http://benalman.com/about/license/ 21 | */ 22 | (function($,h,c){var a=$([]),e=$.resize=$.extend($.resize,{}),i,k="setTimeout",j="resize",d=j+"-special-event",b="delay",f="throttleWindow";e[b]=250;e[f]=true;$.event.special[j]={setup:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.add(l);$.data(this,d,{w:l.width(),h:l.height()});if(a.length===1){g()}},teardown:function(){if(!e[f]&&this[k]){return false}var l=$(this);a=a.not(l);l.removeData(d);if(!a.length){clearTimeout(i)}},add:function(l){if(!e[f]&&this[k]){return false}var n;function m(s,o,p){var q=$(this),r=$.data(this,d);r.w=o!==c?o:q.width();r.h=p!==c?p:q.height();n.apply(this,arguments)}if($.isFunction(l)){n=l;return m}else{n=l.handler;l.handler=m}}};function g(){i=h[k](function(){a.each(function(){var n=$(this),m=n.width(),l=n.height(),o=$.data(this,d);if(m!==o.w||l!==o.h){n.trigger(j,[o.w=m,o.h=l])}});g()},e[b])}})(jQuery,this); 23 | 24 | 25 | (function ($) { 26 | var options = { }; // no options 27 | 28 | function init(plot) { 29 | function onResize() { 30 | var placeholder = plot.getPlaceholder(); 31 | 32 | // somebody might have hidden us and we can't plot 33 | // when we don't have the dimensions 34 | if (placeholder.width() == 0 || placeholder.height() == 0) 35 | return; 36 | 37 | plot.resize(); 38 | plot.setupGrid(); 39 | plot.draw(); 40 | } 41 | 42 | function bindEvents(plot, eventHolder) { 43 | plot.getPlaceholder().resize(onResize); 44 | } 45 | 46 | function shutdown(plot, eventHolder) { 47 | plot.getPlaceholder().unbind("resize", onResize); 48 | } 49 | 50 | plot.hooks.bindEvents.push(bindEvents); 51 | plot.hooks.shutdown.push(shutdown); 52 | } 53 | 54 | $.plot.plugins.push({ 55 | init: init, 56 | options: options, 57 | name: 'resize', 58 | version: '1.0' 59 | }); 60 | })(jQuery); 61 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.symbol.js: -------------------------------------------------------------------------------- 1 | /* 2 | Flot plugin that adds some extra symbols for plotting points. 3 | 4 | The symbols are accessed as strings through the standard symbol 5 | choice: 6 | 7 | series: { 8 | points: { 9 | symbol: "square" // or "diamond", "triangle", "cross" 10 | } 11 | } 12 | 13 | */ 14 | 15 | (function ($) { 16 | function processRawData(plot, series, datapoints) { 17 | // we normalize the area of each symbol so it is approximately the 18 | // same as a circle of the given radius 19 | 20 | var handlers = { 21 | square: function (ctx, x, y, radius, shadow) { 22 | // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 23 | var size = radius * Math.sqrt(Math.PI) / 2; 24 | ctx.rect(x - size, y - size, size + size, size + size); 25 | }, 26 | diamond: function (ctx, x, y, radius, shadow) { 27 | // pi * r^2 = 2s^2 => s = r * sqrt(pi/2) 28 | var size = radius * Math.sqrt(Math.PI / 2); 29 | ctx.moveTo(x - size, y); 30 | ctx.lineTo(x, y - size); 31 | ctx.lineTo(x + size, y); 32 | ctx.lineTo(x, y + size); 33 | ctx.lineTo(x - size, y); 34 | }, 35 | triangle: function (ctx, x, y, radius, shadow) { 36 | // pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3)) 37 | var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3)); 38 | var height = size * Math.sin(Math.PI / 3); 39 | ctx.moveTo(x - size/2, y + height/2); 40 | ctx.lineTo(x + size/2, y + height/2); 41 | if (!shadow) { 42 | ctx.lineTo(x, y - height/2); 43 | ctx.lineTo(x - size/2, y + height/2); 44 | } 45 | }, 46 | cross: function (ctx, x, y, radius, shadow) { 47 | // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 48 | var size = radius * Math.sqrt(Math.PI) / 2; 49 | ctx.moveTo(x - size, y - size); 50 | ctx.lineTo(x + size, y + size); 51 | ctx.moveTo(x - size, y + size); 52 | ctx.lineTo(x + size, y - size); 53 | } 54 | } 55 | 56 | var s = series.points.symbol; 57 | if (handlers[s]) 58 | series.points.symbol = handlers[s]; 59 | } 60 | 61 | function init(plot) { 62 | plot.hooks.processDatapoints.push(processRawData); 63 | } 64 | 65 | $.plot.plugins.push({ 66 | init: init, 67 | name: 'symbols', 68 | version: '1.0' 69 | }); 70 | })(jQuery); 71 | -------------------------------------------------------------------------------- /views/navbar.php: -------------------------------------------------------------------------------- 1 | 52 | 53 | 56 |
  • 57 | 58 | */ 59 | ?> -------------------------------------------------------------------------------- /js/flot/jquery.colorhelpers.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.color={};b.color.make=function(f,e,c,d){var h={};h.r=f||0;h.g=e||0;h.b=c||0;h.a=d!=null?d:1;h.add=function(k,j){for(var g=0;g=1){return"rgb("+[h.r,h.g,h.b].join(",")+")"}else{return"rgba("+[h.r,h.g,h.b,h.a].join(",")+")"}};h.normalize=function(){function g(j,k,i){return ki?i:k)}h.r=g(0,parseInt(h.r),255);h.g=g(0,parseInt(h.g),255);h.b=g(0,parseInt(h.b),255);h.a=g(0,h.a,1);return h};h.clone=function(){return b.color.make(h.r,h.b,h.g,h.a)};return h.normalize()};b.color.extract=function(e,d){var f;do{f=e.css(d).toLowerCase();if(f!=""&&f!="transparent"){break}e=e.parent()}while(!b.nodeName(e.get(0),"body"));if(f=="rgba(0, 0, 0, 0)"){f="transparent"}return b.color.parse(f)};b.color.parse=function(f){var e,c=b.color.make;if(e=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10))}if(e=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10),parseFloat(e[4]))}if(e=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55)}if(e=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55,parseFloat(e[4]))}if(e=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)){return c(parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16))}if(e=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)){return c(parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16))}var d=b.trim(f).toLowerCase();if(d=="transparent"){return c(255,255,255,0)}else{e=a[d]||[0,0,0];return c(e[0],e[1],e[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); -------------------------------------------------------------------------------- /js/bootstrap-dropdown.js: -------------------------------------------------------------------------------- 1 | /* ============================================================ 2 | * bootstrap-dropdown.js v2.0.1 3 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns 4 | * ============================================================ 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* DROPDOWN CLASS DEFINITION 26 | * ========================= */ 27 | 28 | var toggle = '[data-toggle="dropdown"]' 29 | , Dropdown = function ( element ) { 30 | var $el = $(element).on('click.dropdown.data-api', this.toggle) 31 | $('html').on('click.dropdown.data-api', function () { 32 | $el.parent().removeClass('open') 33 | }) 34 | } 35 | 36 | Dropdown.prototype = { 37 | 38 | constructor: Dropdown 39 | 40 | , toggle: function ( e ) { 41 | var $this = $(this) 42 | , selector = $this.attr('data-target') 43 | , $parent 44 | , isActive 45 | 46 | if (!selector) { 47 | selector = $this.attr('href') 48 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 49 | } 50 | 51 | $parent = $(selector) 52 | $parent.length || ($parent = $this.parent()) 53 | 54 | isActive = $parent.hasClass('open') 55 | 56 | clearMenus() 57 | !isActive && $parent.toggleClass('open') 58 | 59 | return false 60 | } 61 | 62 | } 63 | 64 | function clearMenus() { 65 | $(toggle).parent().removeClass('open') 66 | } 67 | 68 | 69 | /* DROPDOWN PLUGIN DEFINITION 70 | * ========================== */ 71 | 72 | $.fn.dropdown = function ( option ) { 73 | return this.each(function () { 74 | var $this = $(this) 75 | , data = $this.data('dropdown') 76 | if (!data) $this.data('dropdown', (data = new Dropdown(this))) 77 | if (typeof option == 'string') data[option].call($this) 78 | }) 79 | } 80 | 81 | $.fn.dropdown.Constructor = Dropdown 82 | 83 | 84 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 85 | * =================================== */ 86 | 87 | $(function () { 88 | $('html').on('click.dropdown.data-api', clearMenus) 89 | $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) 90 | }) 91 | 92 | }( window.jQuery ); -------------------------------------------------------------------------------- /docs/default/_AnemometerModel.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page AnemometerModel.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /AnemometerModel.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | AnemometerModel 45 | 47 | class AnemometerModel 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("QueryExplain.php") 70 | (line 3) 71 | 72 |
    73 | 74 | 75 | 76 |
    77 |
    78 |
    79 | 80 | 81 | 82 | 83 |

    84 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 85 |

    86 |
    87 | -------------------------------------------------------------------------------- /views/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Box Anemometer: Slow Query Log 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 32 | 33 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 72 | 73 | 74 | 75 |
    76 | -------------------------------------------------------------------------------- /docs/AnemometerModel/_AnemometerModel.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page AnemometerModel.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /AnemometerModel.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | AnemometerModel 45 | 47 | class AnemometerModel 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("QueryExplain.php") 70 | (line 3) 71 | 72 |
    73 | 74 | 75 | 76 |
    77 |
    78 |
    79 | 80 | 81 | 82 | 83 |

    84 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 85 |

    86 |
    87 | -------------------------------------------------------------------------------- /docs/li_default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    default
    12 |
    13 | 14 |
    15 | 16 |
    Description
    17 |
    18 | Class trees
    19 | Index of elements
    20 |
    21 | 22 | 23 | 24 |
    Classes
    25 |
    Anemometer
    26 |
    AnemometerModel
    27 |
    Loader
    28 |
    MySQLTableReport
    29 |
    QueryExplain
    30 |
    QueryTableParser
    31 |
    Functions
    32 |
    check_mysql_error
    33 |
    get_var
    34 |
    prettyprint
    35 |
    site_url
    36 |
    Files
    37 |
    Anemometer.php
    38 |
    AnemometerModel.php
    39 |
    Helpers.php
    40 |
    Loader.php
    41 |
    MySQLTableReport.php
    42 |
    QueryExplain.php
    43 |
    QueryTableParser.php
    44 | 45 | 46 |
    47 |
    48 |

    phpDocumentor v 1.4.4

    49 | 50 | -------------------------------------------------------------------------------- /docs/elementindex_Loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

    [Loader] element index

    13 |

    Package indexes

    14 | 22 | All elements 23 |
    24 |
    25 | l 26 | v 27 |
    28 | 29 | 30 |
    31 |
    l
    32 | 33 |
    34 |
    35 |
    36 |
    37 | Loader 38 |
    39 |
    40 |
    Loader in Loader.php
    41 |
    class to mimic codigniter's syntax for loading views from the controller
    42 |
    43 |
    44 | Loader.php 45 |
    46 |
    47 |
    Loader.php in Loader.php
    48 |
    49 |
    50 | 51 |
    52 |
    v
    53 | 54 |
    55 |
    56 |
    57 |
    58 | view 59 |
    60 |
    61 |
    Loader::view() in Loader.php
    62 |
    Finds and displays the given view, and makes the values in $data available to it.
    63 |
    64 |
    65 | 66 |
    67 | l 68 | v 69 |
    70 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | All contributions are welcome to this project. 4 | 5 | ## Contributor License Agreement 6 | 7 | Before a contribution can be merged into this project, please fill out the Contributor License Agreement (CLA) located at: 8 | 9 | http://box.github.io/cla 10 | 11 | To learn more about CLAs and why they are important to open source projects, please see the [Wikipedia entry](http://en.wikipedia.org/wiki/Contributor_License_Agreement). 12 | 13 | ## How to contribute 14 | 15 | * **File an issue** - if you found a bug, want to request an enhancement, or want to implement something (bug fix or feature). 16 | * **Send a pull request** - if you want to contribute code. Please be sure to file an issue first. 17 | 18 | ## Pull request best practices 19 | 20 | We want to accept your pull requests. Please follow these steps: 21 | 22 | ### Step 1: File an issue 23 | 24 | Before writing any code, please file an issue stating the problem you want to solve or the feature you want to implement. This allows us to give you feedback before you spend any time writing code. There may be a known limitation that can't be addressed, or a bug that has already been fixed in a different way. The issue allows us to communicate and figure out if it's worth your time to write a bunch of code for the project. 25 | 26 | ### Step 2: Fork this repository in GitHub 27 | 28 | This will create your own copy of our repository. 29 | 30 | ### Step 3: Add the upstream source 31 | 32 | The upstream source is the project under the Box organization on GitHub. To add an upstream source for this project, type: 33 | 34 | ``` 35 | git remote add upstream git@github.com:Box/Anemometer.git 36 | ``` 37 | 38 | This will come in useful later. 39 | 40 | ### Step 4: Create a feature branch 41 | 42 | Create a branch with a descriptive name, such as `add-search`. 43 | 44 | ### Step 5: Push your feature branch to your fork 45 | 46 | As you develop code, continue to push code to your remote feature branch. Please make sure to include the issue number you're addressing in your commit message, such as: 47 | 48 | ``` 49 | git commit -m "Adding search (fixes #123)" 50 | ``` 51 | 52 | This helps us out by allowing us to track which issue your commit relates to. 53 | 54 | Keep a separate feature branch for each issue you want to address. 55 | 56 | ### Step 6: Rebase 57 | 58 | Before sending a pull request, rebase against upstream, such as: 59 | 60 | ``` 61 | git fetch upstream 62 | git rebase upstream/master 63 | ``` 64 | 65 | This will add your changes on top of what's already in upstream, minimizing merge issues. 66 | 67 | ### Step 7: Run the tests 68 | 69 | Make sure that all tests are passing before submitting a pull request. 70 | 71 | ### Step 8: Send the pull request 72 | 73 | Send the pull request from your feature branch to us. Be sure to include a description that lets us know what work you did. 74 | 75 | Keep in mind that we like to see one issue addressed per pull request, as this helps keep our git history clean and we can more easily track down issues. 76 | -------------------------------------------------------------------------------- /views/report-performance_schema.php: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 |
    " method="GET" class="form-inline"> 15 | 16 | 17 | 18 |
    19 |
    20 | Table Fields
    21 | 36 |
    37 | 38 | 39 |
    40 | Group By
    41 |

    42 | Order By
    43 |

    44 | Having
    45 |

    46 | Limit
    47 |

    48 |
    49 | 50 |
    51 | 52 |
    53 | 54 |
    55 | 59 | 60 | Where
    61 |

    62 | Query Sample Contains
    63 |

    64 | 65 | Digest
    66 |

    67 | 68 |
    69 | 70 |
    71 |
    72 | -------------------------------------------------------------------------------- /css/bootstrap-combobox.css: -------------------------------------------------------------------------------- 1 | .combobox-container { 2 | margin-bottom: 5px; 3 | *zoom: 1; 4 | } 5 | .combobox-container:before, .combobox-container:after { 6 | display: table; 7 | content: ""; 8 | } 9 | .combobox-container:after { 10 | clear: both; 11 | } 12 | .combobox-container input, .combobox-container .uneditable-input { 13 | -webkit-border-radius: 0 3px 3px 0; 14 | -moz-border-radius: 0 3px 3px 0; 15 | border-radius: 0 3px 3px 0; 16 | } 17 | .combobox-container input:focus, .combobox-container .uneditable-input:focus { 18 | position: relative; 19 | z-index: 2; 20 | } 21 | .combobox-container .uneditable-input { 22 | border-left-color: #ccc; 23 | } 24 | .combobox-container .add-on { 25 | float: left; 26 | display: block; 27 | width: auto; 28 | min-width: 16px; 29 | height: 18px; 30 | margin-right: -1px; 31 | padding: 4px 5px; 32 | font-weight: normal; 33 | line-height: 18px; 34 | color: #999999; 35 | text-align: center; 36 | text-shadow: 0 1px 0 #ffffff; 37 | background-color: #f5f5f5; 38 | border: 1px solid #ccc; 39 | -webkit-border-radius: 3px 0 0 3px; 40 | -moz-border-radius: 3px 0 0 3px; 41 | border-radius: 3px 0 0 3px; 42 | } 43 | .combobox-container .active { 44 | background-color: #a9dba9; 45 | border-color: #46a546; 46 | } 47 | .combobox-container input, .combobox-container .uneditable-input { 48 | float: left; 49 | -webkit-border-radius: 3px 0 0 3px; 50 | -moz-border-radius: 3px 0 0 3px; 51 | border-radius: 3px 0 0 3px; 52 | } 53 | .combobox-container .uneditable-input { 54 | border-left-color: #eee; 55 | border-right-color: #ccc; 56 | } 57 | .combobox-container .add-on { 58 | margin-right: 0; 59 | margin-left: -1px; 60 | -webkit-border-radius: 0 3px 3px 0; 61 | -moz-border-radius: 0 3px 3px 0; 62 | border-radius: 0 3px 3px 0; 63 | } 64 | .combobox-container input:first-child { 65 | *margin-left: -160px; 66 | } 67 | .combobox-container input:first-child + .add-on { 68 | *margin-left: -21px; 69 | } 70 | .combobox-container select { 71 | display: inline-block; 72 | width: 0; 73 | height: 0; 74 | border: 0; 75 | padding: 0; 76 | margin: 0; 77 | float: left; 78 | text-indent: -99999px; 79 | *text-indent: 0; 80 | } 81 | .combobox-selected .combobox-clear { 82 | display: inline-block; 83 | } 84 | .combobox-selected .caret { 85 | display: none; 86 | } 87 | .combobox-clear { 88 | display: none; 89 | width: 14px; 90 | height: 14px; 91 | line-height: 14px; 92 | vertical-align: top; 93 | opacity: 0.3; 94 | filter: alpha(opacity=30); 95 | } 96 | .dropdown:hover .combobox-clear, .open.dropdown .combobox-clear { 97 | opacity: 1; 98 | filter: alpha(opacity=100); 99 | } 100 | .btn .combobox-clear { 101 | margin-top: 1px; 102 | margin-left: 1px; 103 | } 104 | .btn:hover .combobox-clear, .open.btn-group .combobox-clear { 105 | opacity: 1; 106 | filter: alpha(opacity=100); 107 | } 108 | .typeahead-long { 109 | max-height: 300px; 110 | overflow-y: auto; 111 | } 112 | -------------------------------------------------------------------------------- /docs/QueryExplain/_QueryExplain.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page QueryExplain.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /QueryExplain.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | QueryExplain 45 | 47 | class QueryExplain rough utility class to get query explain plan and extract table names from abitrary sql so we can run show create table on them. 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("QueryTableParser.php") 70 | (line 3) 71 | 72 |
    73 | 74 | 75 | 76 |
    77 |
    78 |
    79 | 80 | 81 | 82 | 83 |

    84 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 85 |

    86 |
    87 | -------------------------------------------------------------------------------- /views/show_query_perf_schema.php: -------------------------------------------------------------------------------- 1 |

    ">Query

    2 | 3 |
    4 |
    First Seen:
    5 |
    Last Seen:
    6 |
    7 | 8 |
    9 | 10 |
    11 |
    12 | Fingerprint
    13 |
    14 |
    15 |
    16 |
    17 | 18 | 19 | 20 |
    21 | 26 |
    27 |
    28 |
    29 |
    30 |
    31 |
    32 | 33 | 34 | 35 |
    36 | 41 |
    42 |
    43 |
    44 |
    45 |
    46 |
    47 | 48 | 49 |
    50 | 51 |
    52 | 53 | 54 |

    Current Statistics

    55 | 56 | 81 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.selection.min.js: -------------------------------------------------------------------------------- 1 | (function(a){function b(k){var p={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var m={};var r=null;function e(s){if(p.active){l(s);k.getPlaceholder().trigger("plotselecting",[g()])}}function n(s){if(s.which!=1){return}document.body.focus();if(document.onselectstart!==undefined&&m.onselectstart==null){m.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&m.ondrag==null){m.ondrag=document.ondrag;document.ondrag=function(){return false}}d(p.first,s);p.active=true;r=function(t){j(t)};a(document).one("mouseup",r)}function j(s){r=null;if(document.onselectstart!==undefined){document.onselectstart=m.onselectstart}if(document.ondrag!==undefined){document.ondrag=m.ondrag}p.active=false;l(s);if(f()){i()}else{k.getPlaceholder().trigger("plotunselected",[]);k.getPlaceholder().trigger("plotselecting",[null])}return false}function g(){if(!f()){return null}var u={},t=p.first,s=p.second;a.each(k.getAxes(),function(v,w){if(w.used){var y=w.c2p(t[w.direction]),x=w.c2p(s[w.direction]);u[v]={from:Math.min(y,x),to:Math.max(y,x)}}});return u}function i(){var s=g();k.getPlaceholder().trigger("plotselected",[s]);if(s.xaxis&&s.yaxis){k.getPlaceholder().trigger("selected",[{x1:s.xaxis.from,y1:s.yaxis.from,x2:s.xaxis.to,y2:s.yaxis.to}])}}function h(t,u,s){return us?s:u)}function d(w,t){var v=k.getOptions();var u=k.getPlaceholder().offset();var s=k.getPlotOffset();w.x=h(0,t.pageX-u.left-s.left,k.width());w.y=h(0,t.pageY-u.top-s.top,k.height());if(v.selection.mode=="y"){w.x=w==p.first?0:k.width()}if(v.selection.mode=="x"){w.y=w==p.first?0:k.height()}}function l(s){if(s.pageX==null){return}d(p.second,s);if(f()){p.show=true;k.triggerRedrawOverlay()}else{q(true)}}function q(s){if(p.show){p.show=false;k.triggerRedrawOverlay();if(!s){k.getPlaceholder().trigger("plotunselected",[])}}}function c(s,w){var t,y,z,A,x=k.getAxes();for(var u in x){t=x[u];if(t.direction==w){A=w+t.n+"axis";if(!s[A]&&t.n==1){A=w+"axis"}if(s[A]){y=s[A].from;z=s[A].to;break}}}if(!s[A]){t=w=="x"?k.getXAxes()[0]:k.getYAxes()[0];y=s[w+"1"];z=s[w+"2"]}if(y!=null&&z!=null&&y>z){var v=y;y=z;z=v}return{from:y,to:z,axis:t}}function o(t,s){var v,u,w=k.getOptions();if(w.selection.mode=="y"){p.first.x=0;p.second.x=k.width()}else{u=c(t,"x");p.first.x=u.axis.p2c(u.from);p.second.x=u.axis.p2c(u.to)}if(w.selection.mode=="x"){p.first.y=0;p.second.y=k.height()}else{u=c(t,"y");p.first.y=u.axis.p2c(u.from);p.second.y=u.axis.p2c(u.to)}p.show=true;k.triggerRedrawOverlay();if(!s&&f()){i()}}function f(){var s=5;return Math.abs(p.second.x-p.first.x)>=s&&Math.abs(p.second.y-p.first.y)>=s}k.clearSelection=q;k.setSelection=o;k.getSelection=g;k.hooks.bindEvents.push(function(t,s){var u=t.getOptions();if(u.selection.mode!=null){s.mousemove(e);s.mousedown(n)}});k.hooks.drawOverlay.push(function(v,D){if(p.show&&f()){var t=v.getPlotOffset();var s=v.getOptions();D.save();D.translate(t.left,t.top);var z=a.color.parse(s.selection.color);D.strokeStyle=z.scale("a",0.8).toString();D.lineWidth=1;D.lineJoin="round";D.fillStyle=z.scale("a",0.4).toString();var B=Math.min(p.first.x,p.second.x),A=Math.min(p.first.y,p.second.y),C=Math.abs(p.second.x-p.first.x),u=Math.abs(p.second.y-p.first.y);D.fillRect(B,A,C,u);D.strokeRect(B,A,C,u);D.restore()}});k.hooks.shutdown.push(function(t,s){s.unbind("mousemove",e);s.unbind("mousedown",n);if(r){a(document).unbind("mouseup",r)}})}a.plot.plugins.push({init:b,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.1"})})(jQuery); -------------------------------------------------------------------------------- /js/lang-sql.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2008 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 17 | /** 18 | * @fileoverview 19 | * Registers a language handler for SQL. 20 | * 21 | * 22 | * To use, include prettify.js and this file in your HTML page. 23 | * Then put your code in an HTML tag like 24 | *
    (my SQL code)
    25 | * 26 | * 27 | * http://savage.net.au/SQL/sql-99.bnf.html is the basis for the grammar, and 28 | * http://msdn.microsoft.com/en-us/library/aa238507(SQL.80).aspx as the basis 29 | * for the keyword list. 30 | * 31 | * @author mikesamuel@gmail.com 32 | */ 33 | 34 | PR['registerLangHandler']( 35 | PR['createSimpleLexer']( 36 | [ 37 | // Whitespace 38 | [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], 39 | // A double or single quoted, possibly multi-line, string. 40 | [PR['PR_STRING'], /^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/, null, 41 | '"\''] 42 | ], 43 | [ 44 | // A comment is either a line comment that starts with two dashes, or 45 | // two dashes preceding a long bracketed block. 46 | [PR['PR_COMMENT'], /^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/], 47 | [PR['PR_KEYWORD'], /^(?:ADD|ALL|ALTER|AND|ANY|AS|ASC|AUTHORIZATION|BACKUP|BEGIN|BETWEEN|BREAK|BROWSE|BULK|BY|CASCADE|CASE|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMN|COMMIT|COMPUTE|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DBCC|DEALLOCATE|DECLARE|DEFAULT|DELETE|DENY|DESC|DISK|DISTINCT|DISTRIBUTED|DOUBLE|DROP|DUMMY|DUMP|ELSE|END|ERRLVL|ESCAPE|EXCEPT|EXEC|EXECUTE|EXISTS|EXIT|FETCH|FILE|FILLFACTOR|FOR|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GOTO|GRANT|GROUP|HAVING|HOLDLOCK|IDENTITY|IDENTITYCOL|IDENTITY_INSERT|IF|IN|INDEX|INNER|INSERT|INTERSECT|INTO|IS|JOIN|KEY|KILL|LEFT|LIKE|LINENO|LOAD|MATCH|MERGE|NATIONAL|NOCHECK|NONCLUSTERED|NOT|NULL|NULLIF|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPENXML|OPTION|OR|ORDER|OUTER|OVER|PERCENT|PLAN|PRECISION|PRIMARY|PRINT|PROC|PROCEDURE|PUBLIC|RAISERROR|READ|READTEXT|RECONFIGURE|REFERENCES|REPLICATION|RESTORE|RESTRICT|RETURN|REVOKE|RIGHT|ROLLBACK|ROWCOUNT|ROWGUIDCOL|RULE|SAVE|SCHEMA|SELECT|SESSION_USER|SET|SETUSER|SHUTDOWN|SOME|STATISTICS|SYSTEM_USER|TABLE|TEXTSIZE|THEN|TO|TOP|TRAN|TRANSACTION|TRIGGER|TRUNCATE|TSEQUAL|UNION|UNIQUE|UPDATE|UPDATETEXT|USE|USER|USING|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i, null], 48 | // A number is a hex integer literal, a decimal real literal, or in 49 | // scientific notation. 50 | [PR['PR_LITERAL'], 51 | /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i], 52 | // An identifier 53 | [PR['PR_PLAIN'], /^[a-z_][\w-]*/i], 54 | // A run of punctuation 55 | [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/] 56 | ]), 57 | ['sql']); 58 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.threshold.js: -------------------------------------------------------------------------------- 1 | /* 2 | Flot plugin for thresholding data. Controlled through the option 3 | "threshold" in either the global series options 4 | 5 | series: { 6 | threshold: { 7 | below: number 8 | color: colorspec 9 | } 10 | } 11 | 12 | or in a specific series 13 | 14 | $.plot($("#placeholder"), [{ data: [ ... ], threshold: { ... }}]) 15 | 16 | The data points below "below" are drawn with the specified color. This 17 | makes it easy to mark points below 0, e.g. for budget data. 18 | 19 | Internally, the plugin works by splitting the data into two series, 20 | above and below the threshold. The extra series below the threshold 21 | will have its label cleared and the special "originSeries" attribute 22 | set to the original series. You may need to check for this in hover 23 | events. 24 | */ 25 | 26 | (function ($) { 27 | var options = { 28 | series: { threshold: null } // or { below: number, color: color spec} 29 | }; 30 | 31 | function init(plot) { 32 | function thresholdData(plot, s, datapoints) { 33 | if (!s.threshold) 34 | return; 35 | 36 | var ps = datapoints.pointsize, i, x, y, p, prevp, 37 | thresholded = $.extend({}, s); // note: shallow copy 38 | 39 | thresholded.datapoints = { points: [], pointsize: ps }; 40 | thresholded.label = null; 41 | thresholded.color = s.threshold.color; 42 | thresholded.threshold = null; 43 | thresholded.originSeries = s; 44 | thresholded.data = []; 45 | 46 | var below = s.threshold.below, 47 | origpoints = datapoints.points, 48 | addCrossingPoints = s.lines.show; 49 | 50 | threspoints = []; 51 | newpoints = []; 52 | 53 | for (i = 0; i < origpoints.length; i += ps) { 54 | x = origpoints[i] 55 | y = origpoints[i + 1]; 56 | 57 | prevp = p; 58 | if (y < below) 59 | p = threspoints; 60 | else 61 | p = newpoints; 62 | 63 | if (addCrossingPoints && prevp != p && x != null 64 | && i > 0 && origpoints[i - ps] != null) { 65 | var interx = (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]) * (below - y) + x; 66 | prevp.push(interx); 67 | prevp.push(below); 68 | for (m = 2; m < ps; ++m) 69 | prevp.push(origpoints[i + m]); 70 | 71 | p.push(null); // start new segment 72 | p.push(null); 73 | for (m = 2; m < ps; ++m) 74 | p.push(origpoints[i + m]); 75 | p.push(interx); 76 | p.push(below); 77 | for (m = 2; m < ps; ++m) 78 | p.push(origpoints[i + m]); 79 | } 80 | 81 | p.push(x); 82 | p.push(y); 83 | } 84 | 85 | datapoints.points = newpoints; 86 | thresholded.datapoints.points = threspoints; 87 | 88 | if (thresholded.datapoints.points.length > 0) 89 | plot.getData().push(thresholded); 90 | 91 | // FIXME: there are probably some edge cases left in bars 92 | } 93 | 94 | plot.hooks.processDatapoints.push(thresholdData); 95 | } 96 | 97 | $.plot.plugins.push({ 98 | init: init, 99 | options: options, 100 | name: 'threshold', 101 | version: '1.0' 102 | }); 103 | })(jQuery); 104 | -------------------------------------------------------------------------------- /docs/errors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | phpDocumentor Parser Errors and Warnings 7 | 8 | 9 | 10 | 11 | Post-parsing
    12 | AnemometerModel.php
    13 | Helpers.php
    14 | Loader.php
    15 | MySQLTableReport.php
    16 | QueryExplain.php
    17 | QueryTableParser.php
    18 | 19 |

    Anemometer.php

    20 |

    Warnings:


    21 | Warning on line 20 - no @package tag was used in a DocBlock for class Anemometer
    22 | Warning on line 20 - Unknown tag "@created" used
    23 | Warning on line 422 - File "/box/www/anemometer/lib/Anemometer.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    24 | 25 |

    AnemometerModel.php

    26 |

    Warnings:


    27 | Warning on line 15 - Unknown tag "@created" used
    28 | Warning on line 15 - no @package tag was used in a DocBlock for class AnemometerModel
    29 | Warning on line 347 - File "/box/www/anemometer/lib/AnemometerModel.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    30 | 31 |

    Helpers.php

    32 |

    Warnings:


    33 | Warning on line 10 - Unknown tag "@created" used
    34 | Warning on line 17 - no @package tag was used in a DocBlock for file /box/www/anemometer/lib/Helpers.php
    35 | 36 |

    Loader.php

    37 |

    Warnings:


    38 | Warning on line 8 - Unknown tag "@created" used
    39 | Warning on line 9 - no @package tag was used in a DocBlock for class Loader
    40 | Warning on line 49 - File "/box/www/anemometer/lib/Loader.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    41 | 42 |

    MySQLTableReport.php

    43 |

    Warnings:


    44 | Warning on line 95 - no @package tag was used in a DocBlock for class MySQLTableReport
    45 | Warning on line 95 - Unknown tag "@created" used
    46 | Warning on line 975 - File "/box/www/anemometer/lib/MySQLTableReport.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    47 | 48 |

    QueryExplain.php

    49 |

    Warnings:


    50 | Warning on line 44 - Unknown tag "@created" used
    51 | Warning on line 45 - no @package tag was used in a DocBlock for class QueryExplain
    52 | Warning on line 286 - File "/box/www/anemometer/lib/QueryExplain.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    53 | 54 |

    QueryTableParser.php

    55 |

    Warnings:


    56 | Warning on line 21 - no @package tag was used in a DocBlock for class QueryTableParser
    57 | Warning on line 21 - Unknown tag "@created" used
    58 | Warning on line 100 - File "/box/www/anemometer/lib/QueryTableParser.php" has no page-level DocBlock, use @package in the first DocBlock to create one
    59 |

    60 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 61 |

    62 | 63 | -------------------------------------------------------------------------------- /lib/Helpers.php: -------------------------------------------------------------------------------- 1 | 6 | * @license Apache 2.0 license. See LICENSE document for more info 7 | * @created 2012-01-01 8 | */ 9 | 10 | // @todo validation? 11 | /** 12 | * search global request variables $_POST and $_GET in that order and return 13 | * the first defined value for the given key 14 | * 15 | * @param string $name 16 | * @return mixed the value of the variable name (if any) or null. 17 | */ 18 | function get_var($name) 19 | { 20 | $sources = array($_POST, $_GET); 21 | foreach ($sources as $s) 22 | { 23 | if (isset($s[$name])) 24 | { 25 | return $s[$name]; 26 | } 27 | } 28 | return null; 29 | } 30 | 31 | /** 32 | * return the full URL for the base page of the site. 33 | * 34 | * @return string 35 | */ 36 | function site_url() 37 | { 38 | return $_SERVER['SCRIPT_NAME']; 39 | } 40 | 41 | 42 | /** 43 | * wrap html pre tags around the given string, with class="prettyprint" 44 | * 45 | * @param string $string 46 | */ 47 | function prettyprint($string) 48 | { 49 | print '
    ';
     50 |     print $string;
     51 |     print "
    "; 52 | } 53 | 54 | 55 | /** 56 | * die with the error message if the given result handle or mysqli object has an error 57 | * 58 | * @param MySQLi_Result $result 59 | * @param MySQLi $mysqli 60 | */ 61 | function check_mysql_error($result, $mysqli) 62 | { 63 | if (!$result) 64 | { 65 | // @TODO put markup in a view 66 | die("
    ".$mysqli->errno."
    ".$mysqli->error ."
    "); 67 | } 68 | } 69 | 70 | 71 | /** 72 | * Flatten a multiple dim array into a single list 73 | * 74 | * @param array $array 75 | * @return array 76 | */ 77 | 78 | function flatten_array($array) 79 | { 80 | $return = array(); 81 | foreach ($array as $key => $value) { 82 | if (is_array($value)) { 83 | $value = flatten_array($value); 84 | $return = array_merge($return, $value); 85 | } 86 | else 87 | $return[] = $value; 88 | } 89 | return $return; 90 | } 91 | 92 | function dec2hex($str) 93 | { 94 | $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 95 | // Result value 96 | $hexval = ''; 97 | // The quotient of each division operation 98 | $quotient = $str; 99 | $divisor = $str; 100 | // The ending condition 101 | $flag = true; 102 | while($flag) 103 | { 104 | $len = strlen($divisor); 105 | $pos = 1; 106 | $quotient = 0; 107 | // Take the first two digits as temp divisor and advance by 1 each iteration 108 | $div = substr($divisor, 0, 2); 109 | $remainder = $div[0]; 110 | while($pos < $len) 111 | { 112 | // Calculate the next div 113 | $div = $remainder == 0 ? $divisor[$pos] : $remainder.$divisor[$pos]; 114 | $remainder = $div % 16; 115 | $quotient = $quotient.floor($div/16); 116 | $pos++; 117 | } 118 | // Recast the divisor as string to make the $divisor[$pos] work 119 | $quotient = trim_left_zeros($quotient); 120 | $divisor = "$quotient"; 121 | $hexval = $hex[$remainder].$hexval; 122 | // If the divisor is smaller than 15 then end the iteration 123 | if (strlen($divisor)<=2) 124 | { 125 | if ($divisor<15) 126 | { 127 | $flag = false; 128 | } 129 | } 130 | } 131 | $hexval = $hex[$quotient].$hexval; 132 | $hexval = trim_left_zeros($hexval); 133 | // Pad zeros (only because we are using this function for 64-bit integers) 134 | //$hexval = str_repeat('0', 16-strlen($hexval)).$hexval; 135 | return $hexval; 136 | } 137 | 138 | function trim_left_zeros($str) 139 | { 140 | $str = ltrim($str, '0'); 141 | if (empty($str)) 142 | { 143 | $str = '0'; 144 | } 145 | return $str; 146 | } 147 | -------------------------------------------------------------------------------- /docs/default/_Anemometer.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page Anemometer.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /Anemometer.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | Anemometer 45 | 47 | class Anemometer 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("Loader.php") 70 | (line 2) 71 | 72 |
    73 | 74 | 75 | 76 |
    77 | 78 |
    79 | 80 |
    81 | 82 | require 83 | ("AnemometerModel.php") 84 | (line 3) 85 | 86 |
    87 | 88 | 89 | 90 |
    91 | 92 |
    93 | 94 |
    95 | 96 | require 97 | ("MySQLTableReport.php") 98 | (line 4) 99 | 100 |
    101 | 102 | 103 | 104 |
    105 |
    106 |
    107 | 108 | 109 | 110 | 111 |

    112 | Documentation generated on Mon, 12 Mar 2012 11:59:40 -0700 by phpDocumentor 1.4.4 113 |

    114 |
    115 | -------------------------------------------------------------------------------- /docs/Anemometer/_Anemometer.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page Anemometer.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /Anemometer.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | Anemometer 45 | 47 | class Anemometer 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("Loader.php") 70 | (line 2) 71 | 72 |
    73 | 74 | 75 | 76 |
    77 | 78 |
    79 | 80 |
    81 | 82 | require 83 | ("AnemometerModel.php") 84 | (line 3) 85 | 86 |
    87 | 88 | 89 | 90 |
    91 | 92 |
    93 | 94 |
    95 | 96 | require 97 | ("MySQLTableReport.php") 98 | (line 4) 99 | 100 |
    101 | 102 | 103 | 104 |
    105 |
    106 |
    107 | 108 | 109 | 110 | 111 |

    112 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 113 |

    114 |
    115 | -------------------------------------------------------------------------------- /js/bootstrap-tab.js: -------------------------------------------------------------------------------- 1 | /* ======================================================== 2 | * bootstrap-tab.js v2.0.1 3 | * http://twitter.github.com/bootstrap/javascript.html#tabs 4 | * ======================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ======================================================== */ 19 | 20 | 21 | !function( $ ){ 22 | 23 | "use strict" 24 | 25 | /* TAB CLASS DEFINITION 26 | * ==================== */ 27 | 28 | var Tab = function ( element ) { 29 | this.element = $(element) 30 | } 31 | 32 | Tab.prototype = { 33 | 34 | constructor: Tab 35 | 36 | , show: function () { 37 | var $this = this.element 38 | , $ul = $this.closest('ul:not(.dropdown-menu)') 39 | , selector = $this.attr('data-target') 40 | , previous 41 | , $target 42 | 43 | if (!selector) { 44 | selector = $this.attr('href') 45 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 46 | } 47 | 48 | if ( $this.parent('li').hasClass('active') ) return 49 | 50 | previous = $ul.find('.active a').last()[0] 51 | 52 | $this.trigger({ 53 | type: 'show' 54 | , relatedTarget: previous 55 | }) 56 | 57 | $target = $(selector) 58 | 59 | this.activate($this.parent('li'), $ul) 60 | this.activate($target, $target.parent(), function () { 61 | $this.trigger({ 62 | type: 'shown' 63 | , relatedTarget: previous 64 | }) 65 | }) 66 | } 67 | 68 | , activate: function ( element, container, callback) { 69 | var $active = container.find('> .active') 70 | , transition = callback 71 | && $.support.transition 72 | && $active.hasClass('fade') 73 | 74 | function next() { 75 | $active 76 | .removeClass('active') 77 | .find('> .dropdown-menu > .active') 78 | .removeClass('active') 79 | 80 | element.addClass('active') 81 | 82 | if (transition) { 83 | element[0].offsetWidth // reflow for transition 84 | element.addClass('in') 85 | } else { 86 | element.removeClass('fade') 87 | } 88 | 89 | if ( element.parent('.dropdown-menu') ) { 90 | element.closest('li.dropdown').addClass('active') 91 | } 92 | 93 | callback && callback() 94 | } 95 | 96 | transition ? 97 | $active.one($.support.transition.end, next) : 98 | next() 99 | 100 | $active.removeClass('in') 101 | } 102 | } 103 | 104 | 105 | /* TAB PLUGIN DEFINITION 106 | * ===================== */ 107 | 108 | $.fn.tab = function ( option ) { 109 | return this.each(function () { 110 | var $this = $(this) 111 | , data = $this.data('tab') 112 | if (!data) $this.data('tab', (data = new Tab(this))) 113 | if (typeof option == 'string') data[option]() 114 | }) 115 | } 116 | 117 | $.fn.tab.Constructor = Tab 118 | 119 | 120 | /* TAB DATA-API 121 | * ============ */ 122 | 123 | $(function () { 124 | $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 125 | e.preventDefault() 126 | $(this).tab('show') 127 | }) 128 | }) 129 | 130 | }( window.jQuery ); -------------------------------------------------------------------------------- /lib/QueryTableParser.php: -------------------------------------------------------------------------------- 1 | 15 | * @created 2012-01-01 16 | * @license Apache 2.0 license. See LICENSE document for more info 17 | * 18 | * @todo handle table names with spaces wrapped in backticks or quotes 19 | * @todo stop parsing early if possible -- after the JOIN clause (if any) 20 | * @todo ignore token values inside string literals or backticks 21 | */ 22 | class QueryTableParser { 23 | 24 | public $pos; 25 | public $query; 26 | public $len; 27 | public $table_tokens = array( 28 | 'from', 29 | 'join', 30 | 'update', 31 | 'into', 32 | ); 33 | 34 | /** 35 | * parse a query and return an array of table names from it. 36 | * 37 | * @param string $query the sql query 38 | * @return array the list of table names. 39 | */ 40 | public function parse($query) { 41 | $this->query = preg_replace("/\s+/s", " ", $query); 42 | $this->pos = 0; 43 | $this->len = strlen($this->query); 44 | //print "
    ";
     45 |         //print "parsing {$this->query}; length {$this->len}\n";
     46 | 
     47 | 
     48 |         $tables = array();
     49 |         while ($this->has_next_token()) {
     50 |             $token = $this->get_next_token();
     51 |             //print "--> found $token\n";
     52 | 
     53 |             if (in_array(strtolower($token), $this->table_tokens)) {
     54 | 
     55 |                 $table = $this->get_next_token();
     56 |                 
     57 |                 #Handles old style joins
     58 |                 if (preg_match("/,/", $table)) {
     59 |                     while (preg_match("/,/", $table)) {
     60 |                         $table = str_replace(',', '', $table);
     61 |                         if (preg_match("/\w+/", $table)) {
     62 |                             $table = str_replace('`', '', $table);
     63 |                             $tables[$table]=1;
     64 |                         }
     65 |                         $table = $this->get_next_token();
     66 |                     }
     67 |                     if (preg_match("/\w+/", $table)) {
     68 |                         $table = str_replace('`', '', $table);
     69 |                         $tables[$table]=1;
     70 |                     }
     71 |                 }
     72 |                 else {
     73 |                     if (preg_match("/\w+/", $table)) {
     74 |                         $table = str_replace('`', '', $table);
     75 |                         $tables[$table]=1;
     76 |                     }
     77 |                 }
     78 |             }
     79 |         }
     80 |         //print "
    "; 81 | 82 | return array_keys($tables); 83 | } 84 | 85 | /** 86 | * return true if we're not at the end of the string yet. 87 | * @return boolean true if there are more tokens to read 88 | */ 89 | private function has_next_token() { 90 | // at end 91 | if ($this->pos >= $this->len) { 92 | return false; 93 | } 94 | return true; 95 | } 96 | 97 | /** 98 | * returns the next whitespace separated string of characters 99 | * @return string the token value 100 | */ 101 | private function get_next_token() { 102 | // get the pos of the next token boundary 103 | $pos = strpos($this->query, " ", $this->pos); 104 | //print "get next token {$this->pos} {$this->len} {$pos}\n"; 105 | if ($pos === false) { 106 | $pos = $this->len; 107 | } 108 | 109 | // found next boundary 110 | $start = $this->pos; 111 | $len = $pos - $start; 112 | $this->pos = $pos + 1; 113 | return substr($this->query, $start, $len); 114 | } 115 | 116 | } 117 | 118 | ?> 119 | -------------------------------------------------------------------------------- /docs/default/_QueryExplain.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page QueryExplain.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /QueryExplain.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 | 25 |
    26 |
    27 | 28 | 29 |
    30 |
    Classes
    31 | 36 |
    37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 49 | 50 |
    ClassDescription
    44 | QueryExplain 45 | 47 | 48 |
    51 |
    52 |
    53 | 54 | 55 |
    56 |
    Includes
    57 | 62 |
    63 | 64 |
    65 | 66 |
    67 | 68 | require 69 | ("QueryTableParser.php") 70 | (line 45) 71 | 72 |
    73 | 74 | 75 |

    class QueryExplain rough utility class to get query explain plan and extract table names from abitrary sql so we can run show create table on them.

    76 |

    This class needs a user defined method to find the database connection info from the query and a bit of other data stored with the query_review_history table

    The class is used as follows:

    $result = $mysqli->query("SELECT sample, hostname_max, database_max FROM query_review_history WHERE checksum=1"); $row = $result->fetch_assoc();

    $explainer = new QueryExplain($callback, $row); print $explainer->explain();

    where $callback might look like: $callback = function(array $sample) { return array( 'host' => $sample['hostname_max'], 'db' => $sample['database_max'], 'user' => 'username', 'password' => 'password', ); }

    The callback funtion will always take one array argument, and it needs to return and array with the following keys defined: host,db,user,password; and optionally: port

    Because the object takes data associated with one query to return the db connection info, that means a QueryExplain object will always only be valid for one query, and will maintain its own connection

    Sharing connection objects would be advantageous if you want to explain many queries which could be from the same database; but that's not needed for it's current use case.

    77 | 80 | 81 |
    82 |
    83 |
    84 | 85 | 86 | 87 | 88 |

    89 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 90 |

    91 |
    92 | -------------------------------------------------------------------------------- /js/bootstrap-collapse.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap-collapse.js v2.0.1 3 | * http://twitter.github.com/bootstrap/javascript.html#collapse 4 | * ============================================================= 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ============================================================ */ 19 | 20 | !function( $ ){ 21 | 22 | "use strict" 23 | 24 | var Collapse = function ( element, options ) { 25 | this.$element = $(element) 26 | this.options = $.extend({}, $.fn.collapse.defaults, options) 27 | 28 | if (this.options["parent"]) { 29 | this.$parent = $(this.options["parent"]) 30 | } 31 | 32 | this.options.toggle && this.toggle() 33 | } 34 | 35 | Collapse.prototype = { 36 | 37 | constructor: Collapse 38 | 39 | , dimension: function () { 40 | var hasWidth = this.$element.hasClass('width') 41 | return hasWidth ? 'width' : 'height' 42 | } 43 | 44 | , show: function () { 45 | var dimension = this.dimension() 46 | , scroll = $.camelCase(['scroll', dimension].join('-')) 47 | , actives = this.$parent && this.$parent.find('.in') 48 | , hasData 49 | 50 | if (actives && actives.length) { 51 | hasData = actives.data('collapse') 52 | actives.collapse('hide') 53 | hasData || actives.data('collapse', null) 54 | } 55 | 56 | this.$element[dimension](0) 57 | this.transition('addClass', 'show', 'shown') 58 | this.$element[dimension](this.$element[0][scroll]) 59 | 60 | } 61 | 62 | , hide: function () { 63 | var dimension = this.dimension() 64 | this.reset(this.$element[dimension]()) 65 | this.transition('removeClass', 'hide', 'hidden') 66 | this.$element[dimension](0) 67 | } 68 | 69 | , reset: function ( size ) { 70 | var dimension = this.dimension() 71 | 72 | this.$element 73 | .removeClass('collapse') 74 | [dimension](size || 'auto') 75 | [0].offsetWidth 76 | 77 | this.$element.addClass('collapse') 78 | } 79 | 80 | , transition: function ( method, startEvent, completeEvent ) { 81 | var that = this 82 | , complete = function () { 83 | if (startEvent == 'show') that.reset() 84 | that.$element.trigger(completeEvent) 85 | } 86 | 87 | this.$element 88 | .trigger(startEvent) 89 | [method]('in') 90 | 91 | $.support.transition && this.$element.hasClass('collapse') ? 92 | this.$element.one($.support.transition.end, complete) : 93 | complete() 94 | } 95 | 96 | , toggle: function () { 97 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 98 | } 99 | 100 | } 101 | 102 | /* COLLAPSIBLE PLUGIN DEFINITION 103 | * ============================== */ 104 | 105 | $.fn.collapse = function ( option ) { 106 | return this.each(function () { 107 | var $this = $(this) 108 | , data = $this.data('collapse') 109 | , options = typeof option == 'object' && option 110 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 111 | if (typeof option == 'string') data[option]() 112 | }) 113 | } 114 | 115 | $.fn.collapse.defaults = { 116 | toggle: true 117 | } 118 | 119 | $.fn.collapse.Constructor = Collapse 120 | 121 | 122 | /* COLLAPSIBLE DATA-API 123 | * ==================== */ 124 | 125 | $(function () { 126 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 127 | var $this = $(this), href 128 | , target = $this.attr('data-target') 129 | || e.preventDefault() 130 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 131 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 132 | $(target).collapse(option) 133 | }) 134 | }) 135 | 136 | }( window.jQuery ); -------------------------------------------------------------------------------- /lib/QueryRewrite.php: -------------------------------------------------------------------------------- 1 | setQuery($sql); 28 | } 29 | 30 | public function setQuery($sql = null) { 31 | $this->type = self::UNKNOWN; 32 | $this->sql = $sql; 33 | if (is_null($this->sql)) 34 | return; 35 | // Remove comments 36 | $this->sql = preg_replace(self::COMMENTS_C, '', $this->sql); 37 | $this->sql = preg_replace(self::COMMENTS_HASH, '', $this->sql); 38 | $this->sql = preg_replace(self::COMMENTS_SQL, '', $this->sql); 39 | // Remove whitespace 40 | $this->sql = trim($this->sql); 41 | $this->sql = str_replace("\n", " ", $this->sql); 42 | $this->figureOutType(); 43 | } 44 | 45 | private function figureOutType() { 46 | if (preg_match('/^SELECT\s/i', $this->sql)) 47 | $this->type = self::SELECT; 48 | elseif (preg_match('/^DELETE\s+FROM\s/i', $this->sql)) 49 | $this->type = self::DELETE; 50 | elseif (preg_match('/^DELETE\s+'.self::TABLEREF.'\s+FROM\s/i', $this->sql)) 51 | $this->type = self::DELETEMULTI; 52 | elseif (preg_match('/^INSERT\s+INTO\s'.self::TABLEREF.'[\s\(]*SELECT\s+/i', $this->sql)) 53 | $this->type = self::INSERTSELECT; 54 | elseif (preg_match('/^INSERT\s+INTO\s/i', $this->sql)) 55 | $this->type = self::INSERT; 56 | elseif (preg_match('/^(.*)\s+UNION\s+(.*)$/i', $this->sql)) 57 | $this->type = self::UNION; 58 | elseif (preg_match('/^UPDATE\s/i', $this->sql)) 59 | $this->type = self::UPDATE; 60 | elseif (preg_match('/^ALTER\s/i', $this->sql)) 61 | $this->type = self::ALTER; 62 | elseif (preg_match('/^CREATE\s/i', $this->sql)) 63 | $this->type = self::CREATE; 64 | elseif (preg_match('/^DROP\s/i', $this->sql)) 65 | $this->type = self::DROP; 66 | else 67 | $this->type = self::UNKNOWN; 68 | } 69 | 70 | public function getType() { 71 | return $this->type; 72 | } 73 | 74 | public function toSelect() { 75 | switch ($this->type) { 76 | case self::SELECT: 77 | case self::UNION: 78 | $select = $this->sql; 79 | break; 80 | case self::DELETE: 81 | $select = preg_replace('/^DELETE\s+FROM\s/i', 'SELECT 0 FROM ', $this->sql); 82 | break; 83 | case self::DELETEMULTI: 84 | $select = preg_replace('/^DELETE\s+'.self::TABLEREF.'\s+FROM\s/i', 'SELECT 0 FROM ', $this->sql); 85 | break; 86 | case self::UPDATE: 87 | preg_match('/^UPDATE\s+(.*)\s+SET\s+(.*)\s+WHERE\s+(.*)$/i', $this->sql, $subpatterns); 88 | $select = "SELECT {$subpatterns[2]} FROM {$subpatterns[1]} WHERE {$subpatterns[3]}"; 89 | break; 90 | case self::INSERTSELECT: 91 | if (preg_match('/\(\s*(SELECT\s+.*)\)/', $this->sql, $subpatterns)) 92 | $select = trim("{$subpatterns[1]}"); 93 | else 94 | { 95 | preg_match('/^INSERT\s+INTO\s+\w+\s+(SELECT.*)/i', $this->sql, $subpatterns); 96 | $select = trim("{$subpatterns[1]}"); 97 | } 98 | break; 99 | default: 100 | return null; 101 | } 102 | return trim($select); 103 | } 104 | 105 | public function asExplain() { 106 | $sql = $this->toSelect(); 107 | if (is_null($sql)) 108 | return null; 109 | return "EXPLAIN $sql"; 110 | } 111 | 112 | public function asExtendedExplain() { 113 | $sql = $this->toSelect(); 114 | if (is_null($sql)) 115 | return null; 116 | return "EXPLAIN EXTENDED $sql"; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /docs/Loader/Loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs For Class Loader 7 | 8 | 9 | 10 | 11 |
    12 |

    Class Loader

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 |

    class to mimic codigniter's syntax for loading views from the controller

    25 | 28 |

    29 | Located in /Loader.php (line 9) 30 |

    31 | 32 | 33 |
    
     34 | 	
     35 | 			
    36 |
    37 | 38 | 39 | 40 | 41 | 42 |
    43 |
    Method Summary
    44 | 48 |
    49 |
    50 | 51 |
    52 | void 53 | view 54 | (string $view_name, [type $data = null]) 55 |
    56 |
    57 |
    58 |
    59 | 60 | 61 | 62 |
    63 |
    Methods
    64 | 69 |
    70 | 71 | 72 | 73 |
    74 | 75 |
    76 | view (line 25) 77 |
    78 | 79 | 80 |

    Finds and displays the given view, and makes the values in $data available to it.

    81 |

    The name of the view is passed in without the leading "views/" directory or the trailing ".php" extension. So loading a view with $this->view("myview"); would look for a file called "views/myview.php"

    the data is made available my taking the keys of $data, and assigning them to a locally scoped variable of the same name. array( 'title' => 'The Title' ) would be available in the view as $title.

    82 |
      83 |
    • access: public
    • 84 |
    85 | 86 |
    87 | void 88 | 89 | view 90 | 91 | (string $view_name, [type $data = null]) 92 |
    93 | 94 |
      95 |
    • 96 | string 97 | $view_name: The name of the view to load
    • 98 |
    • 99 | type 100 | $data: array of values to make available to the view
    • 101 |
    102 | 103 | 104 |
    105 | 106 |
    107 |
    108 | 109 | 110 |

    111 | Documentation generated on Mon, 12 Mar 2012 11:50:14 -0700 by phpDocumentor 1.4.4 112 |

    113 |
    114 | -------------------------------------------------------------------------------- /docs/default/Loader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs For Class Loader 7 | 8 | 9 | 10 | 11 |
    12 |

    Class Loader

    13 | 14 | 15 |
    16 |
    Description
    17 | 22 |
    23 | 24 |

    class to mimic codigniter's syntax for loading views from the controller

    25 |
      26 |
    • author: Gavin Towey <gavin@box.com>
    • 27 |
    • license: please
    • 28 |
    29 |

    30 | Located in /Loader.php (line 9) 31 |

    32 | 33 | 34 |
    
     35 | 	
     36 | 			
    37 |
    38 | 39 | 40 | 41 | 42 | 43 |
    44 |
    Method Summary
    45 | 49 |
    50 |
    51 | 52 |
    53 | void 54 | view 55 | (string $view_name, [type $data = null]) 56 |
    57 |
    58 |
    59 |
    60 | 61 | 62 | 63 |
    64 |
    Methods
    65 | 70 |
    71 | 72 | 73 | 74 |
    75 | 76 |
    77 | view (line 25) 78 |
    79 | 80 | 81 |

    Finds and displays the given view, and makes the values in $data available to it.

    82 |

    The name of the view is passed in without the leading "views/" directory or the trailing ".php" extension. So loading a view with $this->view("myview"); would look for a file called "views/myview.php"

    the data is made available my taking the keys of $data, and assigning them to a locally scoped variable of the same name. array( 'title' => 'The Title' ) would be available in the view as $title.

    83 |
      84 |
    • access: public
    • 85 |
    86 | 87 |
    88 | void 89 | 90 | view 91 | 92 | (string $view_name, [type $data = null]) 93 |
    94 | 95 |
      96 |
    • 97 | string 98 | $view_name: The name of the view to load
    • 99 |
    • 100 | type 101 | $data: array of values to make available to the view
    • 102 |
    103 | 104 | 105 |
    106 | 107 |
    108 |
    109 | 110 | 111 |

    112 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 113 |

    114 |
    115 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.navigate.min.js: -------------------------------------------------------------------------------- 1 | (function(i){i.fn.drag=function(j,k,l){if(k){this.bind("dragstart",j)}if(l){this.bind("dragend",l)}return !j?this.trigger("drag"):this.bind("drag",k?k:j)};var d=i.event,c=d.special,h=c.drag={not:":input",distance:0,which:1,dragging:false,setup:function(j){j=i.extend({distance:h.distance,which:h.which,not:h.not},j||{});j.distance=e(j.distance);d.add(this,"mousedown",f,j);if(this.attachEvent){this.attachEvent("ondragstart",a)}},teardown:function(){d.remove(this,"mousedown",f);if(this===h.dragging){h.dragging=h.proxy=false}g(this,true);if(this.detachEvent){this.detachEvent("ondragstart",a)}}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}};function f(j){var k=this,l,m=j.data||{};if(m.elem){k=j.dragTarget=m.elem;j.dragProxy=h.proxy||k;j.cursorOffsetX=m.pageX-m.left;j.cursorOffsetY=m.pageY-m.top;j.offsetX=j.pageX-j.cursorOffsetX;j.offsetY=j.pageY-j.cursorOffsetY}else{if(h.dragging||(m.which>0&&j.which!=m.which)||i(j.target).is(m.not)){return}}switch(j.type){case"mousedown":i.extend(m,i(k).offset(),{elem:k,target:j.target,pageX:j.pageX,pageY:j.pageY});d.add(document,"mousemove mouseup",f,m);g(k,false);h.dragging=null;return false;case !h.dragging&&"mousemove":if(e(j.pageX-m.pageX)+e(j.pageY-m.pageY)w){var A=B;B=w;w=A}var y=w-B;if(E&&((E[0]!=null&&yE[1]))){return}D.min=B;D.max=w});o.setupGrid();o.draw();if(!q.preventEvent){o.getPlaceholder().trigger("plotzoom",[o])}};o.pan=function(p){var q={x:+p.left,y:+p.top};if(isNaN(q.x)){q.x=0}if(isNaN(q.y)){q.y=0}b.each(o.getAxes(),function(s,u){var v=u.options,t,r,w=q[u.direction];t=u.c2p(u.p2c(u.min)+w),r=u.c2p(u.p2c(u.max)+w);var x=v.panRange;if(x===false){return}if(x){if(x[0]!=null&&x[0]>t){w=x[0]-t;t+=w;r+=w}if(x[1]!=null&&x[1] 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

    [QueryTableParser] element index

    13 |

    Package indexes

    14 | 22 | All elements 23 |
    24 |
    25 | l 26 | p 27 | q 28 | t 29 |
    30 | 31 | 32 |
    33 |
    l
    34 | 35 |
    36 |
    37 |
    38 |
    39 | $len 40 |
    41 |
    42 |
    QueryTableParser::$len in QueryTableParser.php
    43 |
    44 |
    45 | 46 |
    47 |
    p
    48 | 49 |
    50 |
    51 |
    52 |
    53 | $pos 54 |
    55 |
    56 |
    QueryTableParser::$pos in QueryTableParser.php
    57 |
    58 |
    59 | parse 60 |
    61 |
    62 |
    QueryTableParser::parse() in QueryTableParser.php
    63 |
    parse a query and return an array of table names from it.
    64 |
    65 |
    66 | 67 |
    68 |
    q
    69 | 70 |
    71 |
    72 |
    73 |
    74 | $query 75 |
    76 |
    77 |
    QueryTableParser::$query in QueryTableParser.php
    78 |
    79 |
    80 | QueryTableParser 81 |
    82 |
    83 |
    QueryTableParser in QueryTableParser.php
    84 |
    class QueryTableParser
    85 |
    86 |
    87 | QueryTableParser.php 88 |
    89 |
    90 |
    QueryTableParser.php in QueryTableParser.php
    91 |
    92 |
    93 | 94 |
    95 |
    t
    96 | 97 |
    98 |
    99 |
    100 |
    101 | $table_tokens 102 |
    103 |
    104 |
    QueryTableParser::$table_tokens in QueryTableParser.php
    105 |
    106 |
    107 | 108 |
    109 | l 110 | p 111 | q 112 | t 113 |
    114 | -------------------------------------------------------------------------------- /scripts/anemometer_collect.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env bash 2 | 3 | # anemometer collection script to gather and digest slow query logs 4 | # this is a quick draft script so please give feedback! 5 | # 6 | # basic usage would be to add this to cron like this: 7 | # */5 * * * * anemometer_collect.sh --interval 15 --history-db-host anemometer-db.example.com 8 | # 9 | # This will have to run as a user which has write privileges to the mysql slow log 10 | # 11 | # Additionally there are two sets of permissions to worry about: The local mysql instance, and the remote digest storage instance 12 | # These are handled through defaults files, just create a file in the: my.cnf format such as: 13 | # [client] 14 | # user= 15 | # password= 16 | # 17 | # use --defaults-file for permissions to the local mysql instance 18 | # and use --history-defaults-file for permissions to the remote digest storage instance 19 | # 20 | # 21 | PATH=/usr/local/mariamysql/bin:$PATH 22 | socket= defaults_file= rate_limit= mysqlopts= 23 | interval=30 24 | digest='/usr/bin/pt-query-digest' 25 | #set log prefix 26 | LOG_PREFIX='/usr/local/mariamysql/data/' 27 | #set slow log history file 28 | LOG_HISTORY_FILE='/var/log/slow_query_log_history_3306' 29 | long_query_time=0.1 30 | HOSTNAME=`/sbin/ifconfig | grep 'inet addr' | egrep '172.|192.' | awk '{print $2}' | awk -F ":" '{print $2}'` 31 | PORT=3306 32 | HOSTNAME="$HOSTNAME\:$PORT" 33 | 34 | history_db_host= 35 | history_db_port=3306 36 | history_db_name='slow_query_log' 37 | history_defaults_file= 38 | 39 | help () { 40 | cat < 43 | 44 | Options: 45 | --socket -S The mysql socket to use 46 | --defaults-file The defaults file to use for the client 47 | --interval -i The collection duration 48 | --rate Set log_slow_rate_limit (For Percona MySQL Only) 49 | 50 | --history-db-host Hostname of anemometer database server 51 | --history-db-port Port of anemometer database server 52 | --history-db-name Database name of anemometer database server (Default slow_query_log) 53 | --history-defaults-file Defaults file to pass to pt-query-digest for connecting to the remote anemometer database 54 | EOF 55 | } 56 | 57 | while test $# -gt 0 58 | do 59 | case $1 in 60 | --socket|-S) 61 | socket=$2 62 | shift 63 | ;; 64 | --defaults-file|-f) 65 | defaults_file=$2 66 | shift 67 | ;; 68 | --interval|-i) 69 | interval=$2 70 | shift 71 | ;; 72 | --rate|r) 73 | rate=$2 74 | shift 75 | ;; 76 | --pt-query-digest|-d) 77 | digest=$2 78 | shift 79 | ;; 80 | --help) 81 | help 82 | exit 0 83 | ;; 84 | --history-db-host) 85 | history_db_host=$2 86 | shift 87 | ;; 88 | --history-db-port) 89 | history_db_port=$2 90 | shift 91 | ;; 92 | --history-db-name) 93 | history_db_name=$2 94 | shift 95 | ;; 96 | --history-defaults-file) 97 | history_defaults_file=$2 98 | shift 99 | ;; 100 | *) 101 | echo >&2 "Invalid argument: $1" 102 | ;; 103 | esac 104 | shift 105 | done 106 | 107 | if [ ! -e "${digest}" ]; 108 | then 109 | echo "Error: cannot find digest script at: ${digest}" 110 | exit 1 111 | fi 112 | 113 | if [ ! -z "${defaults_file}" ]; 114 | then 115 | mysqlopts="--defaults-file=${defaults_file}" 116 | fi 117 | 118 | # path to the slow query log 119 | LOG=$( mysql $mysqlopts -e " show global variables like 'slow_query_log_file'" -B | tail -n1 | awk '{ print $2 }' ) 120 | LOG="$LOG_PREFIX$LOG" 121 | if [ $? -ne 0 ]; 122 | then 123 | echo "Error getting slow log file location" 124 | exit 1 125 | fi 126 | 127 | echo "Collecting from slow query log file: ${LOG}" 128 | 129 | # simple 30 second collection 130 | if [ ! -z "${rate}" ]; 131 | then 132 | mysql $mysqlopts -e "SET GLOBAL log_slow_rate_limit=${rate}" 133 | fi 134 | 135 | mysql $mysqlopts -e "SET GLOBAL long_query_time=$long_query_time" 136 | mysql $mysqlopts -e "SET GLOBAL slow_query_log=1" 137 | if [ $? -ne 0 ]; 138 | then 139 | echo "Error: cannot enable slow log. Aborting" 140 | exit 1 141 | fi 142 | echo "Slow log enabled; sleeping for ${interval} seconds" 143 | sleep "${interval}" 144 | 145 | mysql $mysqlopts -e "SET GLOBAL slow_query_log=0" 146 | echo "Done. Processing log and saving to ${history_db_host}:${history_db_port}/${history_db_name}" 147 | 148 | # process the log 149 | if [[ ! -e "$LOG" ]] 150 | then 151 | echo "No slow log to process"; 152 | exit 153 | fi 154 | mv "$LOG" /tmp/tmp_slow_log 155 | 156 | if [ ! -z "${history_defaults_file}" ]; 157 | then 158 | pass_opt="--defaults-file=${history_defaults_file}" 159 | fi 160 | "${digest}" $pass_opt \ 161 | --review h="${history_db_host}",D="$history_db_name",t=global_query_review \ 162 | --history h="${history_db_host}",D="$history_db_name",t=global_query_review_history \ 163 | --no-report --limit=0\% \ 164 | --filter="\$event->{Bytes} = length(\$event->{arg}) and \$event->{hostname}=\"$HOSTNAME\" " \ 165 | "/tmp/tmp_slow_log" 166 | 167 | #store history slow_log 168 | cat /tmp/tmp_slow_log >> $LOG_HISTORY_FILE 169 | -------------------------------------------------------------------------------- /vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "chef/centos-6.5" 14 | config.vm.provision :shell, :path => "bootstrap.sh" 15 | config.vm.network :forwarded_port, host: 8844, guest: 80 16 | 17 | # The url from where the 'config.vm.box' box will be fetched if it 18 | # doesn't already exist on the user's system. 19 | # config.vm.box_url = "http://domain.com/path/to/above.box" 20 | 21 | # Create a forwarded port mapping which allows access to a specific port 22 | # within the machine from a port on the host machine. In the example below, 23 | # accessing "localhost:8080" will access port 80 on the guest machine. 24 | # config.vm.network "forwarded_port", guest: 80, host: 8080 25 | 26 | # Create a private network, which allows host-only access to the machine 27 | # using a specific IP. 28 | # config.vm.network "private_network", ip: "192.168.33.10" 29 | 30 | # Create a public network, which generally matched to bridged network. 31 | # Bridged networks make the machine appear as another physical device on 32 | # your network. 33 | # config.vm.network "public_network" 34 | 35 | # If true, then any SSH connections made will enable agent forwarding. 36 | # Default value: false 37 | # config.ssh.forward_agent = true 38 | 39 | # Share an additional folder to the guest VM. The first argument is 40 | # the path on the host to the actual folder. The second argument is 41 | # the path on the guest to mount the folder. And the optional third 42 | # argument is a set of non-required options. 43 | # config.vm.synced_folder "../data", "/vagrant_data" 44 | 45 | # Provider-specific configuration so you can fine-tune various 46 | # backing providers for Vagrant. These expose provider-specific options. 47 | # Example for VirtualBox: 48 | # 49 | # config.vm.provider "virtualbox" do |vb| 50 | # # Don't boot with headless mode 51 | # vb.gui = true 52 | # 53 | # # Use VBoxManage to customize the VM. For example to change memory: 54 | # vb.customize ["modifyvm", :id, "--memory", "1024"] 55 | # end 56 | # 57 | # View the documentation for the provider you're using for more 58 | # information on available options. 59 | 60 | # Enable provisioning with Puppet stand alone. Puppet manifests 61 | # are contained in a directory path relative to this Vagrantfile. 62 | # You will need to create the manifests directory and a manifest in 63 | # the file chef/centos-6.5.pp in the manifests_path directory. 64 | # 65 | # An example Puppet manifest to provision the message of the day: 66 | # 67 | # # group { "puppet": 68 | # # ensure => "present", 69 | # # } 70 | # # 71 | # # File { owner => 0, group => 0, mode => 0644 } 72 | # # 73 | # # file { '/etc/motd': 74 | # # content => "Welcome to your Vagrant-built virtual machine! 75 | # # Managed by Puppet.\n" 76 | # # } 77 | # 78 | # config.vm.provision "puppet" do |puppet| 79 | # puppet.manifests_path = "manifests" 80 | # puppet.manifest_file = "site.pp" 81 | # end 82 | 83 | # Enable provisioning with chef solo, specifying a cookbooks path, roles 84 | # path, and data_bags path (all relative to this Vagrantfile), and adding 85 | # some recipes and/or roles. 86 | # 87 | # config.vm.provision "chef_solo" do |chef| 88 | # chef.cookbooks_path = "../my-recipes/cookbooks" 89 | # chef.roles_path = "../my-recipes/roles" 90 | # chef.data_bags_path = "../my-recipes/data_bags" 91 | # chef.add_recipe "mysql" 92 | # chef.add_role "web" 93 | # 94 | # # You may also specify custom JSON attributes: 95 | # chef.json = { :mysql_password => "foo" } 96 | # end 97 | 98 | # Enable provisioning with chef server, specifying the chef server URL, 99 | # and the path to the validation key (relative to this Vagrantfile). 100 | # 101 | # The Opscode Platform uses HTTPS. Substitute your organization for 102 | # ORGNAME in the URL and validation key. 103 | # 104 | # If you have your own Chef Server, use the appropriate URL, which may be 105 | # HTTP instead of HTTPS depending on your configuration. Also change the 106 | # validation key to validation.pem. 107 | # 108 | # config.vm.provision "chef_client" do |chef| 109 | # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" 110 | # chef.validation_key_path = "ORGNAME-validator.pem" 111 | # end 112 | # 113 | # If you're using the Opscode platform, your validator client is 114 | # ORGNAME-validator, replacing ORGNAME with your organization name. 115 | # 116 | # If you have your own Chef Server, the default validation client name is 117 | # chef-validator, unless you changed the configuration. 118 | # 119 | # chef.validation_client_name = "ORGNAME-validator" 120 | end 121 | -------------------------------------------------------------------------------- /docs/default/_Helpers.php.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docs for page Helpers.php 7 | 8 | 9 | 10 | 11 |
    12 |

    /Helpers.php

    13 | 14 | 15 |
    16 |
    Description
    17 | 21 |
    22 | 23 |

    Global helper functions for the weatherstation app

    24 |
      25 |
    • author: Gavin Towey <gavin@box.net>
    • 26 |
    • license: please
    • 27 |
    28 | 29 |
    30 |
    31 | 32 | 33 | 34 | 35 | 36 | 37 |
    38 |
    Functions
    39 | 43 |
    44 | 45 |
    46 | 47 |
    48 | check_mysql_error (line 61) 49 |
    50 | 51 | 52 |

    die with the error message if the given result handle or mysqli object has an error

    53 | 54 |
    55 | void 56 | 57 | check_mysql_error 58 | 59 | (MySQLi_Result $result, MySQLi $mysqli) 60 |
    61 | 62 |
      63 |
    • 64 | MySQLi_Result 65 | $result
    • 66 |
    • 67 | MySQLi 68 | $mysqli
    • 69 |
    70 | 71 | 72 |
    73 | 74 |
    75 | 76 |
    77 | get_var (line 18) 78 |
    79 | 80 | 81 |

    search global request variables $_POST and $_GET in that order and return the first defined value for the given key

    82 |
      83 |
    • return: the value of the variable name (if any) or null.
    • 84 |
    85 | 86 |
    87 | mixed 88 | 89 | get_var 90 | 91 | (string $name) 92 |
    93 | 94 |
      95 |
    • 96 | string 97 | $name
    • 98 |
    99 | 100 | 101 |
    102 | 103 |
    104 | 105 |
    106 | prettyprint (line 47) 107 |
    108 | 109 | 110 |

    wrap html pre tags around the given string, with class="prettyprint"

    111 | 112 |
    113 | void 114 | 115 | prettyprint 116 | 117 | (string $string) 118 |
    119 | 120 |
      121 |
    • 122 | string 123 | $string
    • 124 |
    125 | 126 | 127 |
    128 | 129 |
    130 | 131 |
    132 | site_url (line 36) 133 |
    134 | 135 | 136 |

    return the full URL for the base page of the site.

    137 | 138 |
    139 | string 140 | 141 | site_url 142 | 143 | () 144 |
    145 | 146 | 147 | 148 |
    149 |
    150 |
    151 | 152 |

    153 | Documentation generated on Mon, 12 Mar 2012 11:59:41 -0700 by phpDocumentor 1.4.4 154 |

    155 |
    156 | -------------------------------------------------------------------------------- /install.sql: -------------------------------------------------------------------------------- 1 | -- Create the database needed for the Box Anemometer 2 | DROP DATABASE IF EXISTS slow_query_log; 3 | CREATE DATABASE slow_query_log; 4 | USE slow_query_log; 5 | 6 | -- Create the global query review table 7 | CREATE TABLE `global_query_review` ( 8 | `checksum` bigint(20) unsigned NOT NULL, 9 | `fingerprint` text NOT NULL, 10 | `sample` longtext NOT NULL, 11 | `first_seen` datetime DEFAULT NULL, 12 | `last_seen` datetime DEFAULT NULL, 13 | `reviewed_by` varchar(20) DEFAULT NULL, 14 | `reviewed_on` datetime DEFAULT NULL, 15 | `comments` text, 16 | `reviewed_status` varchar(24) DEFAULT NULL, 17 | PRIMARY KEY (`checksum`) 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 19 | 20 | -- Create the historical query review table 21 | CREATE TABLE `global_query_review_history` ( 22 | `hostname_max` varchar(64) NOT NULL, 23 | `db_max` varchar(64) DEFAULT NULL, 24 | `checksum` bigint(20) unsigned NOT NULL, 25 | `sample` longtext NOT NULL, 26 | `ts_min` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 27 | `ts_max` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 28 | `ts_cnt` float DEFAULT NULL, 29 | `Query_time_sum` float DEFAULT NULL, 30 | `Query_time_min` float DEFAULT NULL, 31 | `Query_time_max` float DEFAULT NULL, 32 | `Query_time_pct_95` float DEFAULT NULL, 33 | `Query_time_stddev` float DEFAULT NULL, 34 | `Query_time_median` float DEFAULT NULL, 35 | `Lock_time_sum` float DEFAULT NULL, 36 | `Lock_time_min` float DEFAULT NULL, 37 | `Lock_time_max` float DEFAULT NULL, 38 | `Lock_time_pct_95` float DEFAULT NULL, 39 | `Lock_time_stddev` float DEFAULT NULL, 40 | `Lock_time_median` float DEFAULT NULL, 41 | `Rows_sent_sum` float DEFAULT NULL, 42 | `Rows_sent_min` float DEFAULT NULL, 43 | `Rows_sent_max` float DEFAULT NULL, 44 | `Rows_sent_pct_95` float DEFAULT NULL, 45 | `Rows_sent_stddev` float DEFAULT NULL, 46 | `Rows_sent_median` float DEFAULT NULL, 47 | `Rows_examined_sum` float DEFAULT NULL, 48 | `Rows_examined_min` float DEFAULT NULL, 49 | `Rows_examined_max` float DEFAULT NULL, 50 | `Rows_examined_pct_95` float DEFAULT NULL, 51 | `Rows_examined_stddev` float DEFAULT NULL, 52 | `Rows_examined_median` float DEFAULT NULL, 53 | `Rows_affected_sum` float DEFAULT NULL, 54 | `Rows_affected_min` float DEFAULT NULL, 55 | `Rows_affected_max` float DEFAULT NULL, 56 | `Rows_affected_pct_95` float DEFAULT NULL, 57 | `Rows_affected_stddev` float DEFAULT NULL, 58 | `Rows_affected_median` float DEFAULT NULL, 59 | `Rows_read_sum` float DEFAULT NULL, 60 | `Rows_read_min` float DEFAULT NULL, 61 | `Rows_read_max` float DEFAULT NULL, 62 | `Rows_read_pct_95` float DEFAULT NULL, 63 | `Rows_read_stddev` float DEFAULT NULL, 64 | `Rows_read_median` float DEFAULT NULL, 65 | `Merge_passes_sum` float DEFAULT NULL, 66 | `Merge_passes_min` float DEFAULT NULL, 67 | `Merge_passes_max` float DEFAULT NULL, 68 | `Merge_passes_pct_95` float DEFAULT NULL, 69 | `Merge_passes_stddev` float DEFAULT NULL, 70 | `Merge_passes_median` float DEFAULT NULL, 71 | `InnoDB_IO_r_ops_min` float DEFAULT NULL, 72 | `InnoDB_IO_r_ops_max` float DEFAULT NULL, 73 | `InnoDB_IO_r_ops_pct_95` float DEFAULT NULL, 74 | `InnoDB_IO_r_bytes_pct_95` float DEFAULT NULL, 75 | `InnoDB_IO_r_bytes_stddev` float DEFAULT NULL, 76 | `InnoDB_IO_r_bytes_median` float DEFAULT NULL, 77 | `InnoDB_IO_r_wait_min` float DEFAULT NULL, 78 | `InnoDB_IO_r_wait_max` float DEFAULT NULL, 79 | `InnoDB_IO_r_wait_pct_95` float DEFAULT NULL, 80 | `InnoDB_IO_r_ops_stddev` float DEFAULT NULL, 81 | `InnoDB_IO_r_ops_median` float DEFAULT NULL, 82 | `InnoDB_IO_r_bytes_min` float DEFAULT NULL, 83 | `InnoDB_IO_r_bytes_max` float DEFAULT NULL, 84 | `InnoDB_IO_r_wait_stddev` float DEFAULT NULL, 85 | `InnoDB_IO_r_wait_median` float DEFAULT NULL, 86 | `InnoDB_rec_lock_wait_min` float DEFAULT NULL, 87 | `InnoDB_rec_lock_wait_max` float DEFAULT NULL, 88 | `InnoDB_rec_lock_wait_pct_95` float DEFAULT NULL, 89 | `InnoDB_rec_lock_wait_stddev` float DEFAULT NULL, 90 | `InnoDB_rec_lock_wait_median` float DEFAULT NULL, 91 | `InnoDB_queue_wait_min` float DEFAULT NULL, 92 | `InnoDB_queue_wait_max` float DEFAULT NULL, 93 | `InnoDB_queue_wait_pct_95` float DEFAULT NULL, 94 | `InnoDB_queue_wait_stddev` float DEFAULT NULL, 95 | `InnoDB_queue_wait_median` float DEFAULT NULL, 96 | `InnoDB_pages_distinct_min` float DEFAULT NULL, 97 | `InnoDB_pages_distinct_max` float DEFAULT NULL, 98 | `InnoDB_pages_distinct_pct_95` float DEFAULT NULL, 99 | `InnoDB_pages_distinct_stddev` float DEFAULT NULL, 100 | `InnoDB_pages_distinct_median` float DEFAULT NULL, 101 | `QC_Hit_cnt` float DEFAULT NULL, 102 | `QC_Hit_sum` float DEFAULT NULL, 103 | `Full_scan_cnt` float DEFAULT NULL, 104 | `Full_scan_sum` float DEFAULT NULL, 105 | `Full_join_cnt` float DEFAULT NULL, 106 | `Full_join_sum` float DEFAULT NULL, 107 | `Tmp_table_cnt` float DEFAULT NULL, 108 | `Tmp_table_sum` float DEFAULT NULL, 109 | `Filesort_cnt` float DEFAULT NULL, 110 | `Filesort_sum` float DEFAULT NULL, 111 | `Tmp_table_on_disk_cnt` float DEFAULT NULL, 112 | `Tmp_table_on_disk_sum` float DEFAULT NULL, 113 | `Filesort_on_disk_cnt` float DEFAULT NULL, 114 | `Filesort_on_disk_sum` float DEFAULT NULL, 115 | `Bytes_sum` float DEFAULT NULL, 116 | `Bytes_min` float DEFAULT NULL, 117 | `Bytes_max` float DEFAULT NULL, 118 | `Bytes_pct_95` float DEFAULT NULL, 119 | `Bytes_stddev` float DEFAULT NULL, 120 | `Bytes_median` float DEFAULT NULL, 121 | UNIQUE KEY `hostname_max` (`hostname_max`,`checksum`,`ts_min`,`ts_max`), 122 | KEY `ts_min` (`ts_min`), 123 | KEY `checksum` (`checksum`) 124 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 125 | -------------------------------------------------------------------------------- /js/bootstrap-combobox.js: -------------------------------------------------------------------------------- 1 | /* ============================================================= 2 | * bootstrap-combobox.js v0.9.0 3 | * ============================================================= 4 | * Copyright 2012 Daniel Farrell 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * ============================================================ */ 18 | 19 | !function( $ ) { 20 | 21 | "use strict" 22 | 23 | var Combobox = function ( element, options ) { 24 | this.options = $.extend({}, $.fn.combobox.defaults, options) 25 | this.$container = this.setup(element) 26 | this.$element = this.$container.find('input') 27 | this.$button = this.$container.find('.dropdown-toggle') 28 | this.$target = this.$container.find('select') 29 | this.matcher = this.options.matcher || this.matcher 30 | this.sorter = this.options.sorter || this.sorter 31 | this.highlighter = this.options.highlighter || this.highlighter 32 | this.$menu = $(this.options.menu).appendTo('body') 33 | this.source = this.parse() 34 | this.options.items = this.source.length 35 | this.shown = false 36 | this.listen() 37 | } 38 | 39 | /* NOTE: COMBOBOX EXTENDS BOOTSTRAP-TYPEAHEAD.js 40 | ========================================== */ 41 | 42 | Combobox.prototype = $.extend({}, $.fn.typeahead.Constructor.prototype, { 43 | 44 | constructor: Combobox 45 | 46 | , setup: function (element) { 47 | var select = $(element) 48 | , combobox = $(this.options.template) 49 | select.before(combobox) 50 | select.detach() 51 | combobox.prepend(select) 52 | return combobox 53 | } 54 | 55 | , parse: function () { 56 | var map = {} 57 | , source = [] 58 | , selected = false 59 | this.$element.siblings('select').find('option').each(function() { 60 | var option = $(this) 61 | map[option.html()] = option.val() 62 | source.push(option.html()) 63 | if(option.attr('selected')) selected = option.html() 64 | }) 65 | this.map = map 66 | if (selected) { 67 | this.$element.val(selected) 68 | this.$container.addClass('combobox-selected') 69 | } 70 | return source 71 | } 72 | 73 | , toggle: function () { 74 | if (this.$container.hasClass('combobox-selected')) { 75 | this.$target.val('') 76 | this.$element.val('') 77 | this.$container.removeClass('combobox-selected') 78 | } else { 79 | if (this.shown) { 80 | this.hide() 81 | } else { 82 | this.lookup() 83 | } 84 | } 85 | } 86 | 87 | // modified typeahead function adding container and target handling 88 | , select: function () { 89 | var val = this.$menu.find('.active').attr('data-value') 90 | this.$element.val(val) 91 | this.$container.addClass('combobox-selected') 92 | this.$target.val(this.map[val]) 93 | this.$target.trigger('change') 94 | return this.hide() 95 | } 96 | 97 | // modified typeahead function removing the blank handling 98 | , lookup: function (event) { 99 | var that = this 100 | , items 101 | , q 102 | 103 | this.query = this.$element.val() 104 | 105 | items = $.grep(this.source, function (item) { 106 | if (that.matcher(item)) return item 107 | }) 108 | 109 | items = this.sorter(items) 110 | 111 | if (!items.length) { 112 | return this.shown ? this.hide() : this 113 | } 114 | 115 | return this.render(items.slice(0, this.options.items)).show() 116 | } 117 | 118 | // modified typeahead function adding button handling 119 | , listen: function () { 120 | this.$element 121 | .on('blur', $.proxy(this.blur, this)) 122 | .on('keypress', $.proxy(this.keypress, this)) 123 | .on('keyup', $.proxy(this.keyup, this)) 124 | 125 | if ($.browser.webkit || $.browser.msie) { 126 | this.$element.on('keydown', $.proxy(this.keypress, this)) 127 | } 128 | 129 | this.$menu 130 | .on('click', $.proxy(this.click, this)) 131 | .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 132 | 133 | this.$button 134 | .on('click', $.proxy(this.toggle, this)) 135 | } 136 | 137 | }) 138 | 139 | /* COMBOBOX PLUGIN DEFINITION 140 | * =========================== */ 141 | 142 | $.fn.combobox = function ( option ) { 143 | return this.each(function () { 144 | var $this = $(this) 145 | , data 146 | , options = typeof option == 'object' && option 147 | $this.data('combobox', (data = new Combobox(this, options))) 148 | if (typeof option == 'string') data[option]() 149 | }) 150 | } 151 | 152 | $.fn.combobox.defaults = { 153 | template: '
    ' 154 | , menu: '' 155 | , item: '
  • ' 156 | } 157 | 158 | $.fn.combobox.Constructor = Combobox 159 | 160 | }( window.jQuery ) 161 | -------------------------------------------------------------------------------- /views/report.php: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 | " method="GET" class="form-inline"> 15 | 16 | 17 |
    18 |
    19 | From
    20 |
    21 | 22 | 23 |
    24 |
    25 | 26 | 27 | 28 |
    29 | To
    30 |
    31 | 32 | 33 |
    34 |
    35 | 36 |
    37 | Query first seen since
    38 |
    39 | 40 | 41 |
    42 |
    43 |
    44 |
    45 |
    46 |
    47 | Table Fields
    48 | 73 |
    74 | 75 |
    76 | Filter By Host
    77 |
    83 | 84 | Group By
    85 |

    86 | Order By
    87 |

    88 | Having
    89 |

    90 | Limit
    91 |

    92 |
    93 | 94 |
    95 | 96 |
    97 | 98 |
    99 | 103 | 104 | Where
    105 |

    106 | Query Sample Contains
    107 |

    108 | Reviewed Status
    109 |
    115 | 116 | Audit Status
    117 |
    123 | 124 | Checksum
    125 |

    126 | 127 |
    128 | 129 |
    130 |
    131 | -------------------------------------------------------------------------------- /js/flot/jquery.flot.crosshair.js: -------------------------------------------------------------------------------- 1 | /* 2 | Flot plugin for showing crosshairs, thin lines, when the mouse hovers 3 | over the plot. 4 | 5 | crosshair: { 6 | mode: null or "x" or "y" or "xy" 7 | color: color 8 | lineWidth: number 9 | } 10 | 11 | Set the mode to one of "x", "y" or "xy". The "x" mode enables a 12 | vertical crosshair that lets you trace the values on the x axis, "y" 13 | enables a horizontal crosshair and "xy" enables them both. "color" is 14 | the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"), 15 | "lineWidth" is the width of the drawn lines (default is 1). 16 | 17 | The plugin also adds four public methods: 18 | 19 | - setCrosshair(pos) 20 | 21 | Set the position of the crosshair. Note that this is cleared if 22 | the user moves the mouse. "pos" is in coordinates of the plot and 23 | should be on the form { x: xpos, y: ypos } (you can use x2/x3/... 24 | if you're using multiple axes), which is coincidentally the same 25 | format as what you get from a "plothover" event. If "pos" is null, 26 | the crosshair is cleared. 27 | 28 | - clearCrosshair() 29 | 30 | Clear the crosshair. 31 | 32 | - lockCrosshair(pos) 33 | 34 | Cause the crosshair to lock to the current location, no longer 35 | updating if the user moves the mouse. Optionally supply a position 36 | (passed on to setCrosshair()) to move it to. 37 | 38 | Example usage: 39 | var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; 40 | $("#graph").bind("plothover", function (evt, position, item) { 41 | if (item) { 42 | // Lock the crosshair to the data point being hovered 43 | myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] }); 44 | } 45 | else { 46 | // Return normal crosshair operation 47 | myFlot.unlockCrosshair(); 48 | } 49 | }); 50 | 51 | - unlockCrosshair() 52 | 53 | Free the crosshair to move again after locking it. 54 | */ 55 | 56 | (function ($) { 57 | var options = { 58 | crosshair: { 59 | mode: null, // one of null, "x", "y" or "xy", 60 | color: "rgba(170, 0, 0, 0.80)", 61 | lineWidth: 1 62 | } 63 | }; 64 | 65 | function init(plot) { 66 | // position of crosshair in pixels 67 | var crosshair = { x: -1, y: -1, locked: false }; 68 | 69 | plot.setCrosshair = function setCrosshair(pos) { 70 | if (!pos) 71 | crosshair.x = -1; 72 | else { 73 | var o = plot.p2c(pos); 74 | crosshair.x = Math.max(0, Math.min(o.left, plot.width())); 75 | crosshair.y = Math.max(0, Math.min(o.top, plot.height())); 76 | } 77 | 78 | plot.triggerRedrawOverlay(); 79 | }; 80 | 81 | plot.clearCrosshair = plot.setCrosshair; // passes null for pos 82 | 83 | plot.lockCrosshair = function lockCrosshair(pos) { 84 | if (pos) 85 | plot.setCrosshair(pos); 86 | crosshair.locked = true; 87 | } 88 | 89 | plot.unlockCrosshair = function unlockCrosshair() { 90 | crosshair.locked = false; 91 | } 92 | 93 | function onMouseOut(e) { 94 | if (crosshair.locked) 95 | return; 96 | 97 | if (crosshair.x != -1) { 98 | crosshair.x = -1; 99 | plot.triggerRedrawOverlay(); 100 | } 101 | } 102 | 103 | function onMouseMove(e) { 104 | if (crosshair.locked) 105 | return; 106 | 107 | if (plot.getSelection && plot.getSelection()) { 108 | crosshair.x = -1; // hide the crosshair while selecting 109 | return; 110 | } 111 | 112 | var offset = plot.offset(); 113 | crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); 114 | crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); 115 | plot.triggerRedrawOverlay(); 116 | } 117 | 118 | plot.hooks.bindEvents.push(function (plot, eventHolder) { 119 | if (!plot.getOptions().crosshair.mode) 120 | return; 121 | 122 | eventHolder.mouseout(onMouseOut); 123 | eventHolder.mousemove(onMouseMove); 124 | }); 125 | 126 | plot.hooks.drawOverlay.push(function (plot, ctx) { 127 | var c = plot.getOptions().crosshair; 128 | if (!c.mode) 129 | return; 130 | 131 | var plotOffset = plot.getPlotOffset(); 132 | 133 | ctx.save(); 134 | ctx.translate(plotOffset.left, plotOffset.top); 135 | 136 | if (crosshair.x != -1) { 137 | ctx.strokeStyle = c.color; 138 | ctx.lineWidth = c.lineWidth; 139 | ctx.lineJoin = "round"; 140 | 141 | ctx.beginPath(); 142 | if (c.mode.indexOf("x") != -1) { 143 | ctx.moveTo(crosshair.x, 0); 144 | ctx.lineTo(crosshair.x, plot.height()); 145 | } 146 | if (c.mode.indexOf("y") != -1) { 147 | ctx.moveTo(0, crosshair.y); 148 | ctx.lineTo(plot.width(), crosshair.y); 149 | } 150 | ctx.stroke(); 151 | } 152 | ctx.restore(); 153 | }); 154 | 155 | plot.hooks.shutdown.push(function (plot, eventHolder) { 156 | eventHolder.unbind("mouseout", onMouseOut); 157 | eventHolder.unbind("mousemove", onMouseMove); 158 | }); 159 | } 160 | 161 | $.plot.plugins.push({ 162 | init: init, 163 | options: options, 164 | name: 'crosshair', 165 | version: '1.0' 166 | }); 167 | })(jQuery); 168 | --------------------------------------------------------------------------------