rack-mini-profiler 0.9.2 → 0.9.3
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.
Potentially problematic release.
This version of rack-mini-profiler might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/lib/html/includes.css +15 -4
- data/lib/html/includes.js +93 -58
- data/lib/html/includes.less +21 -5
- data/lib/html/includes.tmpl +49 -49
- data/lib/html/list.tmpl +8 -8
- data/lib/mini_profiler/asset_version.rb +5 -0
- data/lib/mini_profiler/client_settings.rb +3 -3
- data/lib/mini_profiler/config.rb +11 -11
- data/lib/mini_profiler/gc_profiler.rb +10 -10
- data/lib/mini_profiler/profiler.rb +49 -71
- data/lib/mini_profiler/profiling_methods.rb +15 -17
- data/lib/mini_profiler/storage/file_store.rb +4 -4
- data/lib/mini_profiler/storage/memcache_store.rb +5 -7
- data/lib/mini_profiler/storage/memory_store.rb +56 -27
- data/lib/mini_profiler/storage/redis_store.rb +19 -11
- data/lib/mini_profiler/timer_struct/base.rb +33 -0
- data/lib/mini_profiler/timer_struct/client.rb +89 -0
- data/lib/mini_profiler/timer_struct/custom.rb +22 -0
- data/lib/mini_profiler/timer_struct/page.rb +62 -0
- data/lib/mini_profiler/timer_struct/request.rb +126 -0
- data/lib/mini_profiler/timer_struct/sql.rb +59 -0
- data/lib/mini_profiler/version.rb +2 -2
- data/lib/patches/db/activerecord.rb +42 -0
- data/lib/patches/db/moped.rb +12 -0
- data/lib/patches/db/mysql2.rb +30 -0
- data/lib/patches/db/pg.rb +104 -0
- data/lib/patches/db/plucky.rb +47 -0
- data/lib/patches/db/rsolr.rb +24 -0
- data/lib/patches/db/sequel.rb +10 -0
- data/lib/patches/sql_patches.rb +17 -255
- data/lib/rack-mini-profiler.rb +28 -0
- data/rack-mini-profiler.gemspec +6 -2
- metadata +16 -8
- data/lib/mini_profiler/client_timer_struct.rb +0 -78
- data/lib/mini_profiler/custom_timer_struct.rb +0 -22
- data/lib/mini_profiler/page_timer_struct.rb +0 -58
- data/lib/mini_profiler/request_timer_struct.rb +0 -115
- data/lib/mini_profiler/sql_timer_struct.rb +0 -58
- data/lib/mini_profiler/timer_struct.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 915cfa4f71cab960c3f73128fa213cce013f0b65
|
4
|
+
data.tar.gz: 3465e843ef28ed50178f1f76255de96b474903f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c232ba029fb050b15d6b4cdb08b9dc3a6079ed723c06beb7b99dcbc7b6d009822aa2686895661a8e57497a0c5e529a691bf7507c0a895639be9b0e0346ddf29
|
7
|
+
data.tar.gz: 45b90274fd6828441a1a4ca14017a6d3b1f1292b65c157dbd03964748b7fd648b39f06484b36d56fd0340b52498bd9c8b0242fe6063e6e23dd115d4b99c10040
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rack-mini-profiler
|
2
2
|
|
3
|
-
[](https://codeclimate.com/github/MiniProfiler/rack-mini-profiler) [](https://travis-ci.org/MiniProfiler/rack-mini-profiler)
|
4
4
|
|
5
5
|
Middleware that displays speed badge for every html page. Designed to work both in production and in development.
|
6
6
|
|
@@ -23,7 +23,7 @@ We have decided to restructure our repository so there is a central UI repo and
|
|
23
23
|
|
24
24
|
- Setting up a build that reuses https://github.com/MiniProfiler/ui
|
25
25
|
- Migrating the internal data structures [per the spec](https://github.com/MiniProfiler/ui)
|
26
|
-
- Cleaning up the [horrendous class structure that is using strings as keys and crazy non-objects](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/mini_profiler/
|
26
|
+
- Cleaning up the [horrendous class structure that is using strings as keys and crazy non-objects](https://github.com/MiniProfiler/rack-mini-profiler/blob/master/lib/mini_profiler/timer_struct/sql.rb#L36-L44)
|
27
27
|
|
28
28
|
If you feel like taking on any of this start an issue and update us on your progress.
|
29
29
|
|
@@ -87,7 +87,7 @@ end
|
|
87
87
|
|
88
88
|
To generate [flamegraphs](http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler):
|
89
89
|
|
90
|
-
* add the **flamegraph** gem to your Gemfile
|
90
|
+
* add the [**flamegraph**](https://github.com/SamSaffron/flamegraph) gem to your Gemfile
|
91
91
|
* visit a page in your app with `?pp=flamegraph`
|
92
92
|
|
93
93
|
Flamegraph generation is supported in MRI 2.0 and 2.1 only.
|
@@ -112,6 +112,19 @@ Various aspects of rack-mini-profiler's behavior can be configured when your app
|
|
112
112
|
For example in a Rails app, this should be done in an initializer:
|
113
113
|
**config/initializers/mini_profiler.rb**
|
114
114
|
|
115
|
+
### Caching behavior
|
116
|
+
To fix some nasty bugs with rack-mini-profiler showing the wrong data, the middleware
|
117
|
+
will remove headers relating to caching (Date & Etag on responses, If-Modified-Since & If-None-Match on requests).
|
118
|
+
This probably won't ever break your application, but it can cause some unexpected behavior. For
|
119
|
+
example, in a Rails app, calls to `stale?` will always return true.
|
120
|
+
|
121
|
+
To disable this behavior, use the following config setting:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
# Do not let rack-mini-profiler disable caching
|
125
|
+
Rack::MiniProfiler.config.disable_caching = false # defaults to true
|
126
|
+
```
|
127
|
+
|
115
128
|
### Storage
|
116
129
|
|
117
130
|
rack-mini-profiler stores its results so they can be shared later and aren't lost at the end of the request.
|
@@ -167,6 +180,7 @@ The available configuration options are:
|
|
167
180
|
|
168
181
|
* pre_authorize_cb - A lambda callback you can set to determine whether or not mini_profiler should be visible on a given request. Default in a Rails environment is only on in development mode. If in a Rack app, the default is always on.
|
169
182
|
* position - Can either be 'right' or 'left'. Default is 'left'.
|
183
|
+
* skip_paths - Specifies path list that can be skipped.
|
170
184
|
* skip_schema_queries - Whether or not you want to log the queries about the schema of your tables. Default is 'false', 'true' in rails development.
|
171
185
|
* auto_inject (default true) - when false the miniprofiler script is not injected in the page
|
172
186
|
* backtrace_filter - a regex you can use to filter out unwanted lines from the backtraces
|
data/lib/html/includes.css
CHANGED
@@ -149,6 +149,21 @@
|
|
149
149
|
.profiler-result .profiler-queries .profiler-stack-trace {
|
150
150
|
margin-bottom: 15px;
|
151
151
|
}
|
152
|
+
.profiler-result .profiler-queries tbody tr {
|
153
|
+
border-bottom: 1px solid #f1f1f1;
|
154
|
+
}
|
155
|
+
.profiler-result .profiler-queries tr {
|
156
|
+
background-color: #FFF;
|
157
|
+
}
|
158
|
+
.profiler-result .profiler-queries tr.slow {
|
159
|
+
background-color: #FEE;
|
160
|
+
}
|
161
|
+
.profiler-result .profiler-queries tr.very-slow {
|
162
|
+
background-color: #FDD;
|
163
|
+
}
|
164
|
+
.profiler-result .profiler-queries tr.very-very-slow {
|
165
|
+
background-color: #FCC;
|
166
|
+
}
|
152
167
|
.profiler-result .profiler-queries pre {
|
153
168
|
font-family: Consolas, monospace, serif;
|
154
169
|
white-space: pre-wrap;
|
@@ -163,14 +178,10 @@
|
|
163
178
|
.profiler-result .profiler-queries td {
|
164
179
|
padding: 15px;
|
165
180
|
text-align: left;
|
166
|
-
background-color: #fff;
|
167
181
|
}
|
168
182
|
.profiler-result .profiler-queries td:last-child {
|
169
183
|
padding-right: 25px;
|
170
184
|
}
|
171
|
-
.profiler-result .profiler-queries .profiler-odd td {
|
172
|
-
background-color: #e5e5e5;
|
173
|
-
}
|
174
185
|
.profiler-result .profiler-queries .profiler-since-start,
|
175
186
|
.profiler-result .profiler-queries .profiler-duration {
|
176
187
|
text-align: right;
|
data/lib/html/includes.js
CHANGED
@@ -278,7 +278,7 @@ var MiniProfiler = (function () {
|
|
278
278
|
|
279
279
|
var queriesScrollIntoView = function (link, queries, whatToScroll) {
|
280
280
|
var id = link.closest('tr').attr('data-timing-id'),
|
281
|
-
cells = queries.find('tr[data-timing-id="' + id + '"]
|
281
|
+
cells = queries.find('tr[data-timing-id="' + id + '"]');
|
282
282
|
|
283
283
|
// ensure they're in view
|
284
284
|
whatToScroll.scrollTop(whatToScroll.scrollTop() + cells.first().position().top - 100);
|
@@ -326,13 +326,13 @@ var MiniProfiler = (function () {
|
|
326
326
|
if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16)];
|
327
327
|
|
328
328
|
// Look for rgba(0, 0, 0, 0) == transparent in Safari 3
|
329
|
-
if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) return
|
329
|
+
if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) return [0,0,0,0];
|
330
330
|
|
331
331
|
return null;
|
332
332
|
};
|
333
333
|
|
334
334
|
var bindDocumentEvents = function () {
|
335
|
-
$(document).bind('click keyup', function (e) {
|
335
|
+
$(document).bind('click.mini-profiler keyup.mini-profiler', function (e) {
|
336
336
|
|
337
337
|
// this happens on every keystroke, and :visible is crazy expensive in IE <9
|
338
338
|
// and in this case, the display:none check is sufficient.
|
@@ -365,9 +365,19 @@ var MiniProfiler = (function () {
|
|
365
365
|
popupHide(button, popup);
|
366
366
|
}
|
367
367
|
});
|
368
|
-
$(document).bind('keydown', options.toggleShortcut, function(e) {
|
368
|
+
$(document).bind('keydown.mini-profiler', options.toggleShortcut, function(e) {
|
369
369
|
$('.profiler-results').toggle();
|
370
370
|
});
|
371
|
+
|
372
|
+
if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
|
373
|
+
$(document).bind('page:change.mini-profiler', function() {
|
374
|
+
unbindDocumentEvents();
|
375
|
+
});
|
376
|
+
}
|
377
|
+
};
|
378
|
+
|
379
|
+
var unbindDocumentEvents = function() {
|
380
|
+
$(document).unbind('.mini-profiler');
|
371
381
|
};
|
372
382
|
|
373
383
|
var initFullView = function () {
|
@@ -456,11 +466,11 @@ var MiniProfiler = (function () {
|
|
456
466
|
// fetch profile results for any ajax calls
|
457
467
|
// note, this does not use $ cause we want to hook into the main jQuery
|
458
468
|
if (jQuery && jQuery(document) && jQuery(document).ajaxComplete) {
|
459
|
-
jQuery(document).ajaxComplete
|
469
|
+
jQuery(document).bind('ajaxComplete.mini-profiler', jQueryAjaxComplete);
|
460
470
|
}
|
461
471
|
|
462
472
|
if (jQuery && jQuery(document).ajaxStart)
|
463
|
-
jQuery(document).ajaxStart
|
473
|
+
jQuery(document).bind('ajaxStart.mini-profiler', function () { ajaxStartTime = new Date(); });
|
464
474
|
|
465
475
|
// fetch results after ASP Ajax calls
|
466
476
|
if (typeof (Sys) != 'undefined' && typeof (Sys.WebForms) != 'undefined' && typeof (Sys.WebForms.PageRequestManager) != 'undefined') {
|
@@ -534,22 +544,27 @@ var MiniProfiler = (function () {
|
|
534
544
|
var _send = XMLHttpRequest.prototype.send;
|
535
545
|
|
536
546
|
XMLHttpRequest.prototype.send = function sendReplacement(data) {
|
537
|
-
|
547
|
+
if (this.onreadystatechange) {
|
548
|
+
if (typeof (this.miniprofiler) == 'undefined' || typeof (this.miniprofiler.prev_onreadystatechange) == 'undefined') {
|
549
|
+
this.miniprofiler = { prev_onreadystatechange: this.onreadystatechange };
|
538
550
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
551
|
+
this.onreadystatechange = function onReadyStateChangeReplacement() {
|
552
|
+
if (this.readyState == 4) {
|
553
|
+
var stringIds = this.getResponseHeader('X-MiniProfiler-Ids');
|
554
|
+
if (stringIds) {
|
555
|
+
var ids = typeof JSON != 'undefined' ? JSON.parse(stringIds) : eval(stringIds);
|
556
|
+
fetchResults(ids);
|
557
|
+
}
|
558
|
+
}
|
547
559
|
|
548
|
-
|
549
|
-
|
560
|
+
if (this.miniprofiler.prev_onreadystatechange != null)
|
561
|
+
return this.miniprofiler.prev_onreadystatechange.apply(this, arguments);
|
562
|
+
};
|
563
|
+
}
|
564
|
+
}
|
550
565
|
|
551
566
|
return _send.apply(this, arguments);
|
552
|
-
}
|
567
|
+
}
|
553
568
|
}
|
554
569
|
|
555
570
|
// some elements want to be hidden on certain doc events
|
@@ -644,6 +659,16 @@ var MiniProfiler = (function () {
|
|
644
659
|
};
|
645
660
|
|
646
661
|
var init = function() {
|
662
|
+
|
663
|
+
// jquery.hotkeys.js
|
664
|
+
// https://github.com/jeresig/jquery.hotkeys/blob/master/jquery.hotkeys.js
|
665
|
+
|
666
|
+
if (jQuery.hotkeys === undefined) {
|
667
|
+
(function(d){function h(g){if("string"===typeof g.data){var h=g.handler,j=g.data.toLowerCase().split(" ");g.handler=function(b){if(!(this!==b.target&&(/textarea|select/i.test(b.target.nodeName)||"text"===b.target.type))){var c="keypress"!==b.type&&d.hotkeys.specialKeys[b.which],e=String.fromCharCode(b.which).toLowerCase(),a="",f={};b.altKey&&"alt"!==c&&(a+="alt+");b.ctrlKey&&"ctrl"!==c&&(a+="ctrl+");b.metaKey&&(!b.ctrlKey&&"meta"!==c)&&(a+="meta+");b.shiftKey&&"shift"!==c&&(a+="shift+");c?f[a+c]=
|
668
|
+
!0:(f[a+e]=!0,f[a+d.hotkeys.shiftNums[e]]=!0,"shift+"===a&&(f[d.hotkeys.shiftNums[e]]=!0));c=0;for(e=j.length;c<e;c++)if(f[j[c]])return h.apply(this,arguments)}}}}d.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",
|
669
|
+
109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};d.each(["keydown","keyup","keypress"],function(){d.event.special[this]={add:h}})})(MiniProfiler.jQuery);
|
670
|
+
}
|
671
|
+
|
647
672
|
if (options.authorized) {
|
648
673
|
var url = options.path + "includes.css?v=" + options.version;
|
649
674
|
if (document.createStyleSheet) {
|
@@ -660,13 +685,6 @@ var MiniProfiler = (function () {
|
|
660
685
|
doInit();
|
661
686
|
}
|
662
687
|
|
663
|
-
// jquery.hotkeys.js
|
664
|
-
// https://github.com/jeresig/jquery.hotkeys/blob/master/jquery.hotkeys.js
|
665
|
-
|
666
|
-
(function(d){function h(g){if("string"===typeof g.data){var h=g.handler,j=g.data.toLowerCase().split(" ");g.handler=function(b){if(!(this!==b.target&&(/textarea|select/i.test(b.target.nodeName)||"text"===b.target.type))){var c="keypress"!==b.type&&d.hotkeys.specialKeys[b.which],e=String.fromCharCode(b.which).toLowerCase(),a="",f={};b.altKey&&"alt"!==c&&(a+="alt+");b.ctrlKey&&"ctrl"!==c&&(a+="ctrl+");b.metaKey&&(!b.ctrlKey&&"meta"!==c)&&(a+="meta+");b.shiftKey&&"shift"!==c&&(a+="shift+");c?f[a+c]=
|
667
|
-
!0:(f[a+e]=!0,f[a+d.hotkeys.shiftNums[e]]=!0,"shift+"===a&&(f[d.hotkeys.shiftNums[e]]=!0));c=0;for(e=j.length;c<e;c++)if(f[j[c]])return h.apply(this,arguments)}}}}d.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",
|
668
|
-
109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};d.each(["keydown","keyup","keypress"],function(){d.event.special[this]={add:h}})})(MiniProfiler.jQuery);
|
669
|
-
|
670
688
|
};
|
671
689
|
|
672
690
|
var major, minor;
|
@@ -688,11 +706,15 @@ var MiniProfiler = (function () {
|
|
688
706
|
}
|
689
707
|
},
|
690
708
|
|
709
|
+
cleanUp: function() {
|
710
|
+
unbindDocumentEvents();
|
711
|
+
},
|
712
|
+
|
691
713
|
getClientTimingByName: function (clientTiming, name) {
|
692
714
|
|
693
|
-
for (var i = 0; i < clientTiming.
|
694
|
-
if (clientTiming.
|
695
|
-
return clientTiming.
|
715
|
+
for (var i = 0; i < clientTiming.timings.length; i++) {
|
716
|
+
if (clientTiming.timings[i].name == name) {
|
717
|
+
return clientTiming.timings[i];
|
696
718
|
}
|
697
719
|
}
|
698
720
|
return { Name: name, Duration: "", Start: "" };
|
@@ -730,10 +752,10 @@ var MiniProfiler = (function () {
|
|
730
752
|
var list = [];
|
731
753
|
var t;
|
732
754
|
|
733
|
-
if (!clientTimings.
|
755
|
+
if (!clientTimings.timings) return [];
|
734
756
|
|
735
|
-
for (var i = 0; i < clientTimings.
|
736
|
-
t = clientTimings.
|
757
|
+
for (var i = 0; i < clientTimings.timings.length; i++) {
|
758
|
+
t = clientTimings.timings[i];
|
737
759
|
var trivial = t.Name != "Dom Complete" && t.Name != "Response" && t.Name != "First Paint Time";
|
738
760
|
trivial = t.Duration < 2 ? trivial : false;
|
739
761
|
list.push(
|
@@ -752,19 +774,32 @@ var MiniProfiler = (function () {
|
|
752
774
|
getSqlTimings: function (root) {
|
753
775
|
var result = [],
|
754
776
|
addToResults = function (timing) {
|
755
|
-
if (timing.
|
756
|
-
for (var i = 0, sqlTiming; i < timing.
|
757
|
-
sqlTiming = timing.
|
777
|
+
if (timing.sql_timings) {
|
778
|
+
for (var i = 0, sqlTiming; i < timing.sql_timings.length; i++) {
|
779
|
+
sqlTiming = timing.sql_timings[i];
|
758
780
|
|
759
781
|
// HACK: add info about the parent Timing to each SqlTiming so UI can render
|
760
|
-
sqlTiming.
|
782
|
+
sqlTiming.parent_timing_name = timing.name;
|
783
|
+
|
784
|
+
if(sqlTiming.duration_milliseconds > 50) {
|
785
|
+
sqlTiming.row_class = "slow";
|
786
|
+
}
|
787
|
+
|
788
|
+
if(sqlTiming.duration_milliseconds > 200) {
|
789
|
+
sqlTiming.row_class = "very-slow";
|
790
|
+
}
|
791
|
+
|
792
|
+
if(sqlTiming.duration_milliseconds > 400) {
|
793
|
+
sqlTiming.row_class = "very-very-slow";
|
794
|
+
}
|
795
|
+
|
761
796
|
result.push(sqlTiming);
|
762
797
|
}
|
763
798
|
}
|
764
799
|
|
765
|
-
if (timing.
|
766
|
-
for (var i = 0; i < timing.
|
767
|
-
addToResults(timing.
|
800
|
+
if (timing.children) {
|
801
|
+
for (var i = 0; i < timing.children.length; i++) {
|
802
|
+
addToResults(timing.children[i]);
|
768
803
|
}
|
769
804
|
}
|
770
805
|
};
|
@@ -799,16 +834,16 @@ var MiniProfiler = (function () {
|
|
799
834
|
};
|
800
835
|
|
801
836
|
var processTimes = function (elem, parent) {
|
802
|
-
var duration = { start: elem.
|
837
|
+
var duration = { start: elem.start_milliseconds, finish: (elem.start_milliseconds + elem.duration_milliseconds) };
|
803
838
|
elem.richTiming = [duration];
|
804
839
|
if (parent != null) {
|
805
840
|
elem.parent = parent;
|
806
841
|
elem.parent.richTiming = removeDuration(elem.parent.richTiming, duration);
|
807
842
|
}
|
808
843
|
|
809
|
-
if (elem.
|
810
|
-
for (var i = 0; i < elem.
|
811
|
-
processTimes(elem.
|
844
|
+
if (elem.children) {
|
845
|
+
for (var i = 0; i < elem.children.length; i++) {
|
846
|
+
processTimes(elem.children[i], elem);
|
812
847
|
}
|
813
848
|
}
|
814
849
|
};
|
@@ -816,7 +851,7 @@ var MiniProfiler = (function () {
|
|
816
851
|
processTimes(root, null);
|
817
852
|
|
818
853
|
// sort results by time
|
819
|
-
result.sort(function (a, b) { return a.
|
854
|
+
result.sort(function (a, b) { return a.start_milliseconds - b.start_milliseconds; });
|
820
855
|
|
821
856
|
var determineOverlap = function(gap, node) {
|
822
857
|
var overlap = 0;
|
@@ -837,15 +872,15 @@ var MiniProfiler = (function () {
|
|
837
872
|
var determineGap = function (gap, node, match) {
|
838
873
|
var overlap = determineOverlap(gap, node);
|
839
874
|
if (match == null || overlap > match.duration) {
|
840
|
-
match = { name: node.
|
875
|
+
match = { name: node.name, duration: overlap };
|
841
876
|
}
|
842
|
-
else if (match.name == node.
|
877
|
+
else if (match.name == node.name) {
|
843
878
|
match.duration += overlap;
|
844
879
|
}
|
845
880
|
|
846
|
-
if (node.
|
847
|
-
for (var i = 0; i < node.
|
848
|
-
match = determineGap(gap, node.
|
881
|
+
if (node.children) {
|
882
|
+
for (var i = 0; i < node.children.length; i++) {
|
883
|
+
match = determineGap(gap, node.children[i], match);
|
849
884
|
}
|
850
885
|
}
|
851
886
|
return match;
|
@@ -855,14 +890,14 @@ var MiniProfiler = (function () {
|
|
855
890
|
var prev = null;
|
856
891
|
$.each(result, function () {
|
857
892
|
this.prevGap = {
|
858
|
-
duration: (this.
|
893
|
+
duration: (this.start_milliseconds - time).toFixed(2),
|
859
894
|
start: time,
|
860
|
-
finish: this.
|
895
|
+
finish: this.start_milliseconds
|
861
896
|
};
|
862
897
|
|
863
898
|
this.prevGap.topReason = determineGap(this.prevGap, root, null);
|
864
899
|
|
865
|
-
time = this.
|
900
|
+
time = this.start_milliseconds + this.duration_milliseconds;
|
866
901
|
prev = this;
|
867
902
|
});
|
868
903
|
|
@@ -870,9 +905,9 @@ var MiniProfiler = (function () {
|
|
870
905
|
if (result.length > 0) {
|
871
906
|
var me = result[result.length - 1];
|
872
907
|
me.nextGap = {
|
873
|
-
duration: (root.
|
908
|
+
duration: (root.duration_milliseconds - time).toFixed(2),
|
874
909
|
start: time,
|
875
|
-
finish: root.
|
910
|
+
finish: root.duration_milliseconds
|
876
911
|
};
|
877
912
|
me.nextGap.topReason = determineGap(me.nextGap, root, null);
|
878
913
|
}
|
@@ -883,13 +918,13 @@ var MiniProfiler = (function () {
|
|
883
918
|
getSqlTimingsCount: function (root) {
|
884
919
|
var result = 0,
|
885
920
|
countSql = function (timing) {
|
886
|
-
if (timing.
|
887
|
-
result += timing.
|
921
|
+
if (timing.sql_timings) {
|
922
|
+
result += timing.sql_timings.length;
|
888
923
|
}
|
889
924
|
|
890
|
-
if (timing.
|
891
|
-
for (var i = 0; i < timing.
|
892
|
-
countSql(timing.
|
925
|
+
if (timing.children) {
|
926
|
+
for (var i = 0; i < timing.children.length; i++) {
|
927
|
+
countSql(timing.children[i]);
|
893
928
|
}
|
894
929
|
}
|
895
930
|
};
|
data/lib/html/includes.less
CHANGED
@@ -157,6 +157,27 @@
|
|
157
157
|
.profiler-stack-trace {
|
158
158
|
margin-bottom:15px;
|
159
159
|
}
|
160
|
+
|
161
|
+
tbody tr {
|
162
|
+
border-bottom: 1px solid #f1f1f1;
|
163
|
+
}
|
164
|
+
|
165
|
+
tr {
|
166
|
+
background-color: #FFF;
|
167
|
+
}
|
168
|
+
|
169
|
+
tr.slow {
|
170
|
+
background-color: #FEE;
|
171
|
+
}
|
172
|
+
|
173
|
+
tr.very-slow {
|
174
|
+
background-color: #FDD;
|
175
|
+
}
|
176
|
+
|
177
|
+
tr.very-very-slow {
|
178
|
+
background-color: #FCC;
|
179
|
+
}
|
180
|
+
|
160
181
|
pre {
|
161
182
|
font-family:@codeFonts;
|
162
183
|
white-space:pre-wrap;
|
@@ -173,17 +194,12 @@
|
|
173
194
|
td {
|
174
195
|
padding:15px;
|
175
196
|
text-align:left;
|
176
|
-
background-color:#fff;
|
177
197
|
|
178
198
|
&:last-child {
|
179
199
|
padding-right:25px; // compensate for scrollbars
|
180
200
|
}
|
181
201
|
}
|
182
202
|
|
183
|
-
.profiler-odd td {
|
184
|
-
background-color:#e5e5e5;
|
185
|
-
}
|
186
|
-
|
187
203
|
.profiler-since-start, .profiler-duration {
|
188
204
|
text-align:right;
|
189
205
|
}
|
data/lib/html/includes.tmpl
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
<div class="profiler-result">
|
4
4
|
|
5
|
-
<div class="profiler-button {{if
|
6
|
-
{{if
|
5
|
+
<div class="profiler-button {{if has_duplicate_sql_timings}}profiler-warning{{/if}}">
|
6
|
+
{{if has_duplicate_sql_timings}}<span class="profiler-nuclear">!</span>{{/if}}
|
7
7
|
<span class="profiler-number">
|
8
|
-
${MiniProfiler.formatDuration(
|
8
|
+
${MiniProfiler.formatDuration(duration_milliseconds)} <span class="profiler-unit">ms</span>
|
9
9
|
</span>
|
10
10
|
</div>
|
11
11
|
|
12
12
|
<div class="profiler-popup">
|
13
13
|
<div class="profiler-info">
|
14
14
|
<span class="profiler-name">
|
15
|
-
${
|
15
|
+
${name} <span class="profiler-overall-duration">(${MiniProfiler.formatDuration(duration_milliseconds)} ms)</span>
|
16
16
|
</span>
|
17
|
-
<span class="profiler-server-time">${
|
17
|
+
<span class="profiler-server-time">${machine_name} on ${MiniProfiler.renderDate(started)}</span>
|
18
18
|
</div>
|
19
19
|
<div class="profiler-output">
|
20
20
|
<table class="profiler-timings">
|
@@ -24,41 +24,41 @@
|
|
24
24
|
<th>duration (ms)</th>
|
25
25
|
<th class="profiler-duration-with-children">with children (ms)</th>
|
26
26
|
<th class="time-from-start">from start (ms)</th>
|
27
|
-
{{if
|
27
|
+
{{if has_sql_timings}}
|
28
28
|
<th colspan="2">query time (ms)</th>
|
29
29
|
{{/if}}
|
30
|
-
{{each
|
30
|
+
{{each custom_timing_names}}
|
31
31
|
<th colspan="2">${$value.toLowerCase()} (ms)</th>
|
32
32
|
{{/each}}
|
33
33
|
</tr>
|
34
34
|
</thead>
|
35
35
|
<tbody>
|
36
|
-
{{tmpl({timing:
|
36
|
+
{{tmpl({timing:root, page:this.data}) "#timingTemplate"}}
|
37
37
|
</tbody>
|
38
38
|
<tfoot>
|
39
39
|
<tr>
|
40
40
|
<td colspan="3">
|
41
|
-
{{if !
|
41
|
+
{{if !client_timings}}
|
42
42
|
{{tmpl "#linksTemplate"}}
|
43
43
|
{{/if}}
|
44
44
|
<a class="profiler-toggle-duration-with-children" title="toggles column with aggregate child durations">show time with children</a>
|
45
45
|
</td>
|
46
|
-
{{if
|
47
|
-
<td colspan="2" class="profiler-number profiler-percent-in-sql" title="${MiniProfiler.getSqlTimingsCount(
|
48
|
-
${MiniProfiler.formatDuration(
|
46
|
+
{{if has_sql_timings}}
|
47
|
+
<td colspan="2" class="profiler-number profiler-percent-in-sql" title="${MiniProfiler.getSqlTimingsCount(root)} queries spent ${MiniProfiler.formatDuration(duration_milliseconds_in_sql)} ms of total request time">
|
48
|
+
${MiniProfiler.formatDuration(duration_milliseconds_in_sql / duration_milliseconds * 100)}
|
49
49
|
<span class="profiler-unit">% in sql</span>
|
50
50
|
</td>
|
51
51
|
{{/if}}
|
52
|
-
{{each
|
53
|
-
<td colspan="2" class="profiler-number profiler-percentage-in-sql" title="${
|
54
|
-
${MiniProfiler.formatDuration(
|
52
|
+
{{each custom_timing_names}}
|
53
|
+
<td colspan="2" class="profiler-number profiler-percentage-in-sql" title="${custom_timing_stats[$value].count} ${$value.toLowerCase()} invocations spent ${MiniProfiler.formatDuration(custom_timing_stats[$value].duration)} ms of total request time">
|
54
|
+
${MiniProfiler.formatDuration(custom_timing_stats[$value].duration / duration_milliseconds * 100)}
|
55
55
|
<span class="profiler-unit">% in ${$value.toLowerCase()}</span>
|
56
56
|
</td>
|
57
57
|
{{/each}}
|
58
58
|
</tr>
|
59
59
|
</tfoot>
|
60
60
|
</table>
|
61
|
-
{{if
|
61
|
+
{{if client_timings}}
|
62
62
|
<table class="profiler-timings profiler-client-timings">
|
63
63
|
<thead>
|
64
64
|
<tr>
|
@@ -68,7 +68,7 @@
|
|
68
68
|
</tr>
|
69
69
|
</thead>
|
70
70
|
<tbody>
|
71
|
-
{{each MiniProfiler.getClientTimings(
|
71
|
+
{{each MiniProfiler.getClientTimings(client_timings)}}
|
72
72
|
<tr class="{{if $value.isTrivial }}profiler-trivial{{/if}}">
|
73
73
|
<td class="profiler-label">${$value.name}</td>
|
74
74
|
<td class="profiler-duration">
|
@@ -92,7 +92,7 @@
|
|
92
92
|
</div>
|
93
93
|
</div>
|
94
94
|
|
95
|
-
{{if
|
95
|
+
{{if has_sql_timings}}
|
96
96
|
<div class="profiler-queries">
|
97
97
|
<table>
|
98
98
|
<thead>
|
@@ -102,7 +102,7 @@
|
|
102
102
|
</tr>
|
103
103
|
</thead>
|
104
104
|
<tbody>
|
105
|
-
{{each(i, s) MiniProfiler.getSqlTimings(
|
105
|
+
{{each(i, s) MiniProfiler.getSqlTimings(root)}}
|
106
106
|
{{tmpl({ g:s.prevGap }) "#sqlGapTemplate"}}
|
107
107
|
{{tmpl({ i:i, s:s }) "#sqlTimingTemplate"}}
|
108
108
|
{{if s.nextGap}}
|
@@ -122,12 +122,12 @@
|
|
122
122
|
</script>
|
123
123
|
|
124
124
|
<script id="linksTemplate" type="text/x-jquery-tmpl">
|
125
|
-
<a href="${MiniProfiler.shareUrl(
|
126
|
-
{{if
|
127
|
-
<a href="${
|
125
|
+
<a href="${MiniProfiler.shareUrl(id)}" class="profiler-share-profiler-results" target="_blank">share</a>
|
126
|
+
{{if custom_link}}
|
127
|
+
<a href="${custom_link}" class="profiler-custom-link" target="_blank">${custom_link_name}</a>
|
128
128
|
{{/if}}
|
129
|
-
{{if
|
130
|
-
<a class="profiler-toggle-trivial" data-show-on-load="${
|
129
|
+
{{if has_trivial_timings}}
|
130
|
+
<a class="profiler-toggle-trivial" data-show-on-load="${has_all_trivial_timings}" title="toggles any rows with < ${trivial_duration_threshold_milliseconds} ms">
|
131
131
|
show trivial
|
132
132
|
</a>
|
133
133
|
{{/if}}
|
@@ -135,41 +135,41 @@
|
|
135
135
|
|
136
136
|
<script id="timingTemplate" type="text/x-jquery-tmpl">
|
137
137
|
|
138
|
-
<tr class="{{if timing.
|
139
|
-
<td class="profiler-label" title="{{if timing.
|
140
|
-
<span class="profiler-indent">${MiniProfiler.renderIndent(timing.
|
138
|
+
<tr class="{{if timing.is_trivial }}profiler-trivial{{/if}}" data-timing-id="${timing.id}">
|
139
|
+
<td class="profiler-label" title="{{if timing.name && timing.name.length > 45 }}${timing.name}{{/if}}">
|
140
|
+
<span class="profiler-indent">${MiniProfiler.renderIndent(timing.depth)}</span> ${timing.name.slice(0,45)}{{if timing.name && timing.name.length > 45 }}...{{/if}}
|
141
141
|
</td>
|
142
142
|
<td class="profiler-duration" title="duration of this step without any children's durations">
|
143
|
-
${MiniProfiler.formatDuration(timing.
|
143
|
+
${MiniProfiler.formatDuration(timing.duration_without_children_milliseconds)}
|
144
144
|
</td>
|
145
145
|
<td class="profiler-duration profiler-duration-with-children" title="duration of this step and its children">
|
146
|
-
${MiniProfiler.formatDuration(timing.
|
146
|
+
${MiniProfiler.formatDuration(timing.duration_milliseconds)}
|
147
147
|
</td>
|
148
148
|
<td class="profiler-duration time-from-start" title="time elapsed since profiling started">
|
149
|
-
<span class="profiler-unit">+</span>${MiniProfiler.formatDuration(timing.
|
149
|
+
<span class="profiler-unit">+</span>${MiniProfiler.formatDuration(timing.start_milliseconds)}
|
150
150
|
</td>
|
151
151
|
|
152
|
-
{{if timing.
|
153
|
-
<td class="profiler-duration {{if timing.
|
152
|
+
{{if timing.has_sql_timings}}
|
153
|
+
<td class="profiler-duration {{if timing.has_duplicate_sql_timings}}profiler-warning{{/if}}" title="{{if timing.has_duplicate_sql_timings}}duplicate queries detected - {{/if}}{{if timing.executed_readers > 0 || timing.executed_scalars > 0 || timing.executed_non_queries > 0}}${timing.executed_readers} reader, ${timing.executed_scalars} scalar, ${timing.executed_non_queries} non-query statements executed{{/if}}">
|
154
154
|
<a class="profiler-queries-show">
|
155
|
-
{{if timing.
|
156
|
-
${timing.
|
155
|
+
{{if timing.has_duplicate_sql_timings}}<span class="profiler-nuclear">!</span>{{/if}}
|
156
|
+
${timing.sql_timings.length} <span class="profiler-unit">sql</span>
|
157
157
|
</a>
|
158
158
|
</td>
|
159
159
|
<td class="profiler-duration" title="aggregate duration of all queries in this step (excludes children)">
|
160
|
-
${MiniProfiler.formatDuration(timing.
|
160
|
+
${MiniProfiler.formatDuration(timing.sql_timings_duration_milliseconds)}
|
161
161
|
</td>
|
162
162
|
{{else}}
|
163
163
|
<td colspan="2"></td>
|
164
164
|
{{/if}}
|
165
165
|
|
166
|
-
{{each page.
|
167
|
-
{{if timing.
|
166
|
+
{{each page.custom_timing_names}}
|
167
|
+
{{if timing.custom_timings && timing.custom_timings[$value]}}
|
168
168
|
<td class="profiler-duration" title="aggregate number of all ${$value.toLowerCase()} invocations in this step (excludes children)">
|
169
|
-
${timing.
|
169
|
+
${timing.custom_timings[$value].length} ${$value.toLowerCase()}
|
170
170
|
</td>
|
171
171
|
<td class="profiler-duration" title="aggregate duration of all ${$value.toLowerCase()} invocations in this step (excludes children)">
|
172
|
-
${MiniProfiler.formatDuration(timing.
|
172
|
+
${MiniProfiler.formatDuration(timing.custom_timing_stats[$value].duration)}
|
173
173
|
</td>
|
174
174
|
{{else}}
|
175
175
|
<td colspan="2"></td>
|
@@ -178,8 +178,8 @@
|
|
178
178
|
|
179
179
|
</tr>
|
180
180
|
|
181
|
-
{{if timing.
|
182
|
-
{{each timing.
|
181
|
+
{{if timing.has_children}}
|
182
|
+
{{each timing.children}}
|
183
183
|
{{tmpl({timing: $value, page: page}) "#timingTemplate"}}
|
184
184
|
{{/each}}
|
185
185
|
{{/if}}
|
@@ -188,20 +188,20 @@
|
|
188
188
|
|
189
189
|
<script id="sqlTimingTemplate" type="text/x-jquery-tmpl">
|
190
190
|
|
191
|
-
<tr class="{
|
191
|
+
<tr class="${s.row_class}" data-timing-id="${s.parent_timing_id}">
|
192
192
|
<td class="profiler-info">
|
193
|
-
<div>${s.
|
194
|
-
<div class="profiler-number"><span class="profiler-unit">T+</span>${MiniProfiler.formatDuration(s.
|
193
|
+
<div>${s.parent_timing_name}</div>
|
194
|
+
<div class="profiler-number"><span class="profiler-unit">T+</span>${MiniProfiler.formatDuration(s.start_milliseconds)} <span class="profiler-unit">ms</span></div>
|
195
195
|
<div>
|
196
|
-
{{if s.
|
197
|
-
${MiniProfiler.renderExecuteType(s.
|
196
|
+
{{if s.is_duplicate}}<span class="profiler-warning">DUPLICATE</span>{{/if}}
|
197
|
+
${MiniProfiler.renderExecuteType(s.execute_type)}
|
198
198
|
</div>
|
199
|
-
<div title="{{if s.
|
199
|
+
<div title="{{if s.execute_type == 3}}first result fetched: ${s.first_fetch_duration_milliseconds}ms{{/if}}">${MiniProfiler.formatDuration(s.duration_milliseconds)} <span class="profiler-unit">ms</span></div>
|
200
200
|
</td>
|
201
201
|
<td>
|
202
202
|
<div class="query">
|
203
|
-
<pre class="profiler-stack-trace">${s.
|
204
|
-
<pre class="prettyprint lang-sql"><code>${s.
|
203
|
+
<pre class="profiler-stack-trace">${s.stack_trace_snippet}</pre>
|
204
|
+
<pre class="prettyprint lang-sql"><code>${s.formatted_command_string} </code></pre>
|
205
205
|
</div>
|
206
206
|
</td>
|
207
207
|
</tr>
|