rack-bug 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/History.txt +0 -0
- data/MIT-LICENSE.txt +19 -0
- data/README.rdoc +29 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/lib/rack/bug.rb +43 -0
- data/lib/rack/bug/options.rb +89 -0
- data/lib/rack/bug/panel.rb +50 -0
- data/lib/rack/bug/panel_app.rb +33 -0
- data/lib/rack/bug/panels/active_record_panel.rb +45 -0
- data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +18 -0
- data/lib/rack/bug/panels/cache_panel.rb +50 -0
- data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
- data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
- data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
- data/lib/rack/bug/panels/log_panel.rb +39 -0
- data/lib/rack/bug/panels/log_panel/rails_extension.rb +11 -0
- data/lib/rack/bug/panels/memory_panel.rb +27 -0
- data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
- data/lib/rack/bug/panels/redis_panel.rb +44 -0
- data/lib/rack/bug/panels/redis_panel/redis_extension.rb +14 -0
- data/lib/rack/bug/panels/redis_panel/stats.rb +48 -0
- data/lib/rack/bug/panels/request_variables_panel.rb +25 -0
- data/lib/rack/bug/panels/sql_panel.rb +55 -0
- data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
- data/lib/rack/bug/panels/sql_panel/query.rb +73 -0
- data/lib/rack/bug/panels/sql_panel/sql_extension.rb +11 -0
- data/lib/rack/bug/panels/templates_panel.rb +44 -0
- data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +12 -0
- data/lib/rack/bug/panels/templates_panel/rendering.rb +67 -0
- data/lib/rack/bug/panels/templates_panel/trace.rb +34 -0
- data/lib/rack/bug/panels/timer_panel.rb +40 -0
- data/lib/rack/bug/params_signature.rb +65 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
- data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +215 -0
- data/lib/rack/bug/public/__rack_bug__/bug.css +211 -0
- data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
- data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
- data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
- data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
- data/lib/rack/bug/render.rb +66 -0
- data/lib/rack/bug/toolbar.rb +137 -0
- data/lib/rack/bug/views/error.html.erb +16 -0
- data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
- data/lib/rack/bug/views/panels/cache.html.erb +93 -0
- data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/log.html.erb +23 -0
- data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
- data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
- data/lib/rack/bug/views/panels/redis.html.erb +32 -0
- data/lib/rack/bug/views/panels/request_variables.html.erb +107 -0
- data/lib/rack/bug/views/panels/sql.html.erb +43 -0
- data/lib/rack/bug/views/panels/templates.html.erb +7 -0
- data/lib/rack/bug/views/panels/timer.html.erb +19 -0
- data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
- data/lib/rack/bug/views/redirect.html.erb +16 -0
- data/lib/rack/bug/views/toolbar.html.erb +42 -0
- data/rack-bug.gemspec +126 -0
- data/spec/fixtures/config.ru +8 -0
- data/spec/fixtures/dummy_panel.rb +2 -0
- data/spec/fixtures/sample_app.rb +29 -0
- data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
- data/spec/rack/bug/panels/cache_panel_spec.rb +159 -0
- data/spec/rack/bug/panels/log_panel_spec.rb +25 -0
- data/spec/rack/bug/panels/memory_panel_spec.rb +21 -0
- data/spec/rack/bug/panels/rails_info_panel_spec.rb +25 -0
- data/spec/rack/bug/panels/redis_panel_spec.rb +57 -0
- data/spec/rack/bug/panels/sql_panel_spec.rb +136 -0
- data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
- data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
- data/spec/rack/toolbar_spec.rb +100 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +70 -0
- metadata +143 -0
@@ -0,0 +1 @@
|
|
1
|
+
(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,cells[i]);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,node){var l=parsers.length;for(var i=1;i<l;i++){if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)){return parsers[i];}}return parsers[0];}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=table.tBodies[0].rows[i],cols=[];cache.row.push($(c));for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));}cols.push(i);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){if(!node)return"";var t="";if(config.textExtraction=="simple"){if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){t=node.childNodes[0].innerHTML;}else{t=node.innerHTML;}}else{if(typeof(config.textExtraction)=="function"){t=config.textExtraction(node);}else{t=$(node).text();}}return t;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){rows.push(r[n[i][checkCell]]);if(!table.config.appender){var o=r[n[i][checkCell]];var l=o.length;for(var j=0;j<l;j++){tableBody[0].appendChild(o[j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false,tableHeadersRows=[];for(var i=0;i<table.tHead.rows.length;i++){tableHeadersRows[i]=0;};$tableHeaders=$("thead th",table);$tableHeaders.each(function(index){this.count=0;this.column=index;this.order=formatSortingOrder(table.config.sortInitialOrder);if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(!this.sortDisabled){$(this).addClass(table.config.cssHeader);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){i=(v.toLowerCase()=="desc")?1:0;}else{i=(v==(0||1))?v:0;}return i;}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(getCachedSortType(table.config.parsers,c)=="text")?((order==0)?"sortText":"sortTextDesc"):((order==0)?"sortNumeric":"sortNumericDesc");var e="e"+i;dynamicExp+="var "+e+" = "+s+"(a["+c+"],b["+c+"]); ";dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function sortText(a,b){return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){var DECIMAL='\\'+config.decimal;var exp='/(^[+]?0('+DECIMAL+'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)'+DECIMAL+'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*'+DECIMAL+'0+$)/';return RegExp(exp).test($.trim(s));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}$("tr:visible",table.tBodies[0]).filter(':even').removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]).end().filter(':odd').removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
|
Binary file
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
module Bug
|
5
|
+
|
6
|
+
module Render
|
7
|
+
include ERB::Util
|
8
|
+
|
9
|
+
def signed_params(hash)
|
10
|
+
ParamsSignature.sign(request, hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
module CompiledTemplates
|
14
|
+
end
|
15
|
+
include CompiledTemplates
|
16
|
+
|
17
|
+
def render_template(filename, local_assigns = {})
|
18
|
+
compile(filename, local_assigns)
|
19
|
+
render_symbol = method_name(filename, local_assigns)
|
20
|
+
send(render_symbol, local_assigns)
|
21
|
+
end
|
22
|
+
|
23
|
+
def compile(filename, local_assigns)
|
24
|
+
render_symbol = method_name(filename, local_assigns)
|
25
|
+
|
26
|
+
if !CompiledTemplates.instance_methods.include?(render_symbol.to_s)
|
27
|
+
compile!(filename, local_assigns)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def compile!(filename, local_assigns)
|
32
|
+
render_symbol = method_name(filename, local_assigns)
|
33
|
+
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
|
34
|
+
|
35
|
+
source = <<-end_src
|
36
|
+
def #{render_symbol}(local_assigns)
|
37
|
+
#{locals_code}
|
38
|
+
#{compiled_source(filename)}
|
39
|
+
end
|
40
|
+
end_src
|
41
|
+
|
42
|
+
CompiledTemplates.module_eval(source, filename, 0)
|
43
|
+
end
|
44
|
+
|
45
|
+
def compiled_source(filename)
|
46
|
+
::ERB.new(::File.read(::File.dirname(__FILE__) + "/../bug/views/#{filename}.html.erb"), nil, "-").src
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_name(filename, local_assigns)
|
50
|
+
if local_assigns && local_assigns.any?
|
51
|
+
method_name = method_name_without_locals(filename).dup
|
52
|
+
method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
|
53
|
+
else
|
54
|
+
method_name = method_name_without_locals(filename)
|
55
|
+
end
|
56
|
+
method_name.to_sym
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_name_without_locals(filename)
|
60
|
+
filename.split("/").join("_")
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "ipaddr"
|
2
|
+
require "digest"
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
module Bug
|
6
|
+
class RackStaticBugAvoider
|
7
|
+
def initialize(app, static_app)
|
8
|
+
@app = app
|
9
|
+
@static_app = static_app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
if env["PATH_INFO"]
|
14
|
+
@static_app.call(env)
|
15
|
+
else
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Toolbar
|
22
|
+
include Options
|
23
|
+
include Render
|
24
|
+
|
25
|
+
MIME_TYPES = ["text/html", "application/xhtml+xml"]
|
26
|
+
|
27
|
+
def initialize(app, options = {})
|
28
|
+
@app = asset_server(app)
|
29
|
+
initialize_options options
|
30
|
+
instance_eval(&block) if block_given?
|
31
|
+
end
|
32
|
+
|
33
|
+
def asset_server(app)
|
34
|
+
RackStaticBugAvoider.new(app, Rack::Static.new(app, :urls => ["/__rack_bug__"], :root => public_path))
|
35
|
+
end
|
36
|
+
|
37
|
+
def public_path
|
38
|
+
::File.expand_path(::File.dirname(__FILE__) + "/../bug/public")
|
39
|
+
end
|
40
|
+
|
41
|
+
def call(env)
|
42
|
+
env.replace @default_options.merge(env)
|
43
|
+
@env = env
|
44
|
+
@original_request = Request.new(@env)
|
45
|
+
|
46
|
+
if toolbar_requested? && ip_authorized? && password_authorized?
|
47
|
+
dispatch
|
48
|
+
else
|
49
|
+
pass
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def pass
|
54
|
+
@app.call(@env)
|
55
|
+
end
|
56
|
+
|
57
|
+
def dispatch
|
58
|
+
@env["rack-bug.panels"] = []
|
59
|
+
|
60
|
+
Rack::Bug.enable
|
61
|
+
status, headers, body = builder.call(@env)
|
62
|
+
Rack::Bug.disable
|
63
|
+
|
64
|
+
@response = Rack::Response.new(body, status, headers)
|
65
|
+
|
66
|
+
if @response.redirect? && options["rack-bug.intercept_redirects"]
|
67
|
+
intercept_redirect
|
68
|
+
elsif modify?
|
69
|
+
inject_toolbar
|
70
|
+
end
|
71
|
+
|
72
|
+
return @response.to_a
|
73
|
+
end
|
74
|
+
|
75
|
+
def intercept_redirect
|
76
|
+
redirect_to = @response.location
|
77
|
+
new_body = render_template("redirect", :redirect_to => @response.location)
|
78
|
+
new_response = Rack::Response.new(new_body, 200, { "Content-Type" => "text/html" })
|
79
|
+
new_response["Content-Length"] = new_body.size.to_s
|
80
|
+
@response = new_response
|
81
|
+
end
|
82
|
+
|
83
|
+
def toolbar_requested?
|
84
|
+
@original_request.cookies["rack_bug_enabled"]
|
85
|
+
end
|
86
|
+
|
87
|
+
def ip_authorized?
|
88
|
+
return true unless options["rack-bug.ip_masks"]
|
89
|
+
|
90
|
+
options["rack-bug.ip_masks"].any? do |ip_mask|
|
91
|
+
ip_mask.include?(IPAddr.new(@original_request.ip))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def password_authorized?
|
96
|
+
return true unless options["rack-bug.password"]
|
97
|
+
|
98
|
+
expected_sha = Digest::SHA1.hexdigest ["rack_bug", options["rack-bug.password"]].join(":")
|
99
|
+
actual_sha = @original_request.cookies["rack_bug_password"]
|
100
|
+
|
101
|
+
actual_sha == expected_sha
|
102
|
+
end
|
103
|
+
|
104
|
+
def modify?
|
105
|
+
@response.ok? &&
|
106
|
+
@env["X-Requested-With"] != "XMLHttpRequest" &&
|
107
|
+
MIME_TYPES.include?(@response.content_type.split(";").first)
|
108
|
+
end
|
109
|
+
|
110
|
+
def builder
|
111
|
+
builder = Rack::Builder.new
|
112
|
+
|
113
|
+
options["rack-bug.panel_classes"].each do |panel_class|
|
114
|
+
builder.use panel_class
|
115
|
+
end
|
116
|
+
|
117
|
+
builder.run @app
|
118
|
+
|
119
|
+
return builder
|
120
|
+
end
|
121
|
+
|
122
|
+
def inject_toolbar
|
123
|
+
full_body = @response.body.join
|
124
|
+
full_body.sub! /<\/body>/, render + "</body>"
|
125
|
+
|
126
|
+
@response["Content-Length"] = full_body.size.to_s
|
127
|
+
@response.body = [full_body]
|
128
|
+
end
|
129
|
+
|
130
|
+
def render
|
131
|
+
render_template("toolbar", :panels => @env["rack-bug.panels"].reverse)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<script type="text/javascript" charset="utf-8">
|
2
|
+
if (typeof jQuery == 'undefined') {
|
3
|
+
var jquery_url = '/__rack_bug__/jquery-1.3.2.js';
|
4
|
+
document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E'));
|
5
|
+
}
|
6
|
+
</script>
|
7
|
+
<script type="text/javascript" src="/__rack_bug__/bug.js"></script>
|
8
|
+
<style type="text/css" media="screen">
|
9
|
+
@import url(/__rack_bug__/bug.css);
|
10
|
+
</style>
|
11
|
+
|
12
|
+
<div id="rack_bug" class="rack_bug_error">
|
13
|
+
<div id="rack_bug_toolbar">
|
14
|
+
<p>There was an error within Rack::Bug!</p>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h3>ActiveRecord Objects</h3>
|
2
|
+
<table class="sortable">
|
3
|
+
<thead>
|
4
|
+
<tr>
|
5
|
+
<th>Count</th>
|
6
|
+
<th>Class</th>
|
7
|
+
</tr>
|
8
|
+
</thead>
|
9
|
+
<tbody>
|
10
|
+
<% records.each do |class_name, count| %>
|
11
|
+
<tr>
|
12
|
+
<td><%= count %></td>
|
13
|
+
<td><%= class_name %></td>
|
14
|
+
</tr>
|
15
|
+
<% end %>
|
16
|
+
</tbody>
|
17
|
+
</table>
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<h3>Cache Usage</h3>
|
2
|
+
<table id="cache_usage">
|
3
|
+
<colgroup>
|
4
|
+
<col width="12%"/>
|
5
|
+
<col width="12%"/>
|
6
|
+
<col width="12%"/>
|
7
|
+
<col width="12%"/>
|
8
|
+
<col width="12%"/>
|
9
|
+
<col width="12%"/>
|
10
|
+
<col width="12%"/>
|
11
|
+
<col width="12%"/>
|
12
|
+
</colgroup>
|
13
|
+
<tr>
|
14
|
+
<th>Total Calls</th>
|
15
|
+
<td><%= stats.calls %></td>
|
16
|
+
|
17
|
+
<th>Total Time</th>
|
18
|
+
<td><%= stats.display_time %></td>
|
19
|
+
|
20
|
+
<th>Hits</th>
|
21
|
+
<td><%= stats.hits %></td>
|
22
|
+
|
23
|
+
<th>Misses</th>
|
24
|
+
<td><%= stats.misses %></td>
|
25
|
+
</tr>
|
26
|
+
<tr>
|
27
|
+
<th>gets</th>
|
28
|
+
<td><%= stats.gets %></td>
|
29
|
+
|
30
|
+
<th>sets</th>
|
31
|
+
<td><%= stats.sets %></td>
|
32
|
+
|
33
|
+
<th>deletes</th>
|
34
|
+
<td><%= stats.deletes %></td>
|
35
|
+
|
36
|
+
<th>get_multis</th>
|
37
|
+
<td><%= stats.get_multis %></td>
|
38
|
+
</tr>
|
39
|
+
</table>
|
40
|
+
|
41
|
+
<% if stats.queries.any? %>
|
42
|
+
<h3>Breakdown</h3>
|
43
|
+
<table id="cache_breakdown" class="sortable">
|
44
|
+
<thead>
|
45
|
+
<tr>
|
46
|
+
<th>Time (ms)</th>
|
47
|
+
<th>Type</th>
|
48
|
+
<th>Parameters</th>
|
49
|
+
<th>Function</th>
|
50
|
+
<th>
|
51
|
+
<a href="/__rack_bug__/delete_cache_list?<%= signed_params(stats.queries_to_param) %>" class="rb_delete_cache">
|
52
|
+
Delete All
|
53
|
+
</a>
|
54
|
+
</th>
|
55
|
+
</tr>
|
56
|
+
</thead>
|
57
|
+
<tbody>
|
58
|
+
<% i = 1 %>
|
59
|
+
<% stats.queries.each do |query| %>
|
60
|
+
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
61
|
+
<td><%= query.display_time %></td>
|
62
|
+
<td><%= query.method %></td>
|
63
|
+
<td><%= query.display_keys %></td>
|
64
|
+
<td></td>
|
65
|
+
<td>
|
66
|
+
<a href="/__rack_bug__/view_cache?<%= signed_params("key" => query.keys.first) %>" class="remote_call">View</a> |
|
67
|
+
<a href="/__rack_bug__/delete_cache?<%= signed_params("key" => query.keys.first) %>" class="rb_delete_cache">Delete</a>
|
68
|
+
</td>
|
69
|
+
</tr>
|
70
|
+
<% i += 1 %>
|
71
|
+
<% end %>
|
72
|
+
</tbody>
|
73
|
+
</table>
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
<script type="text/javascript" charset="utf-8">
|
77
|
+
jQuery(function () {
|
78
|
+
jQuery("#rack_bug .rb_delete_cache").click(function (evt) {
|
79
|
+
jQuery.ajax({
|
80
|
+
url: this.href,
|
81
|
+
beforeSend: function() {
|
82
|
+
jQuery(evt.target).parent("td, th").addClass("rack_bug_spinner");
|
83
|
+
},
|
84
|
+
success: function () {
|
85
|
+
jQuery(evt.target).parent("td, th").removeClass("rack_bug_spinner");
|
86
|
+
jQuery(evt.target).replaceWith("Deleted");
|
87
|
+
}
|
88
|
+
});
|
89
|
+
|
90
|
+
return false;
|
91
|
+
});
|
92
|
+
});
|
93
|
+
</script>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<a class="back" href="">« Back</a>
|
2
|
+
|
3
|
+
<h3>SQL Results</h3>
|
4
|
+
|
5
|
+
<dl>
|
6
|
+
<dt>Executed SQL</dt>
|
7
|
+
<dd><pre><%=h query %></pre></dd>
|
8
|
+
|
9
|
+
<dt>Time</dt>
|
10
|
+
<dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
|
11
|
+
</dl>
|
12
|
+
|
13
|
+
<table class="sortable">
|
14
|
+
<thead>
|
15
|
+
<tr>
|
16
|
+
<% result.fetch_fields.each do |field| %>
|
17
|
+
<th><%= field.name.upcase %></th>
|
18
|
+
<% end %>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody>
|
22
|
+
<% i = 1 %>
|
23
|
+
<% result.each do |row| %>
|
24
|
+
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
25
|
+
<% row.each do |value| %>
|
26
|
+
<td><%= value %></td>
|
27
|
+
<% end %>
|
28
|
+
</tr>
|
29
|
+
<% i += 1 %>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
</table>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<a class="back" href="">« Back</a>
|
2
|
+
|
3
|
+
<h3>SQL Explained</h3>
|
4
|
+
|
5
|
+
<dl>
|
6
|
+
<dt>Executed SQL</dt>
|
7
|
+
<dd><pre><%=h query %></pre></dd>
|
8
|
+
|
9
|
+
<dt>Time</dt>
|
10
|
+
<dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
|
11
|
+
</dl>
|
12
|
+
|
13
|
+
<table class="sortable">
|
14
|
+
<thead>
|
15
|
+
<tr>
|
16
|
+
<% result.fetch_fields.each do |field| %>
|
17
|
+
<th><%= field.name.upcase %></th>
|
18
|
+
<% end %>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody>
|
22
|
+
<% i = 1 %>
|
23
|
+
<% result.each do |row| %>
|
24
|
+
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
25
|
+
<% row.each do |value| %>
|
26
|
+
<td><%= value %></td>
|
27
|
+
<% end %>
|
28
|
+
</tr>
|
29
|
+
<% i += 1 %>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
</table>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h3>Log Messages</h3>
|
2
|
+
<table>
|
3
|
+
<thead>
|
4
|
+
<tr>
|
5
|
+
<th>Level</th>
|
6
|
+
<th>Time</th>
|
7
|
+
<th>Message</th>
|
8
|
+
<th>Location</th>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% i = 1 %>
|
13
|
+
<% logs.each do |log| %>
|
14
|
+
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
15
|
+
<td></td>
|
16
|
+
<td></td>
|
17
|
+
<td><%= log.to_s.gsub(/\e\[[;\d]+m/, "") %></td>
|
18
|
+
<td></td>
|
19
|
+
</tr>
|
20
|
+
<% i += 1 %>
|
21
|
+
<% end %>
|
22
|
+
</tbody>
|
23
|
+
</table>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<a class="back" href="">« Back</a>
|
2
|
+
|
3
|
+
<h3>SQL Profiled</h3>
|
4
|
+
|
5
|
+
<dl>
|
6
|
+
<dt>Executed SQL</dt>
|
7
|
+
<dd><pre><%=h query %></pre></dd>
|
8
|
+
|
9
|
+
<dt>Time</dt>
|
10
|
+
<dd><%=h "%.2f" % (time * 1_000) %>ms</dd>
|
11
|
+
</dl>
|
12
|
+
|
13
|
+
<table class="sortable">
|
14
|
+
<thead>
|
15
|
+
<tr>
|
16
|
+
<% result.fetch_fields.each do |field| %>
|
17
|
+
<th><%= field.name.upcase %></th>
|
18
|
+
<% end %>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody>
|
22
|
+
<% i = 1 %>
|
23
|
+
<% result.each do |row| %>
|
24
|
+
<tr class="<%= i % 2 == 0 ? "even" : "odd" %>">
|
25
|
+
<% row.each do |value| %>
|
26
|
+
<td><%= value %></td>
|
27
|
+
<% end %>
|
28
|
+
</tr>
|
29
|
+
<% i += 1 %>
|
30
|
+
<% end %>
|
31
|
+
</tbody>
|
32
|
+
</table>
|