rack-mini-profiler 0.1.3 → 0.1.8
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.
- data/CHANGELOG +15 -0
- data/README.md +18 -0
- data/lib/html/includes.css +75 -1
- data/lib/html/includes.js +14 -2
- data/lib/html/includes.less +1 -1
- data/lib/html/profile_handler.js +9 -9
- data/lib/mini_profiler/client_timer_struct.rb +38 -3
- data/lib/mini_profiler/config.rb +2 -1
- data/lib/mini_profiler/context.rb +10 -0
- data/lib/mini_profiler/page_timer_struct.rb +7 -3
- data/lib/mini_profiler/profiler.rb +161 -144
- data/lib/mini_profiler/profiling_methods.rb +73 -0
- data/lib/mini_profiler/request_timer_struct.rb +39 -8
- data/lib/mini_profiler/sql_timer_struct.rb +13 -2
- data/lib/mini_profiler/storage/file_store.rb +8 -7
- data/lib/mini_profiler/storage/memory_store.rb +0 -4
- data/lib/mini_profiler_rails/railtie.rb +41 -2
- data/lib/patches/sql_patches.rb +154 -34
- data/lib/rack-mini-profiler.rb +3 -3
- data/rack-mini-profiler.gemspec +3 -4
- metadata +6 -6
- data/lib/html/MiniProfilerHandler.cs +0 -419
- data/lib/mini_profiler/body_add_proxy.rb +0 -45
data/CHANGELOG
CHANGED
@@ -15,3 +15,18 @@
|
|
15
15
|
* Added option to display full backtraces pp=full-backtrace
|
16
16
|
* Cleaned up railties, got rid of the post authorize callback
|
17
17
|
* Version 0.1.3
|
18
|
+
|
19
|
+
12-July-2012 - Sam
|
20
|
+
|
21
|
+
* Fixed incorrect profiling steps (was not indenting or measuring start time right
|
22
|
+
* Implemented native PG and MySql2 interceptors, this gives way more accurate times
|
23
|
+
* Refactored context so its a proper class and not a hash
|
24
|
+
* Added some more client probing built in to rails
|
25
|
+
* More tests
|
26
|
+
|
27
|
+
18-July-2012 - Sam
|
28
|
+
|
29
|
+
* Added First Paint time for chrome
|
30
|
+
* Bug fix to ensure non Rails installs have mini profiler
|
31
|
+
* Version 0.1.7
|
32
|
+
|
data/README.md
CHANGED
@@ -47,6 +47,24 @@ class MyApp < Sinatra::Base
|
|
47
47
|
end
|
48
48
|
```
|
49
49
|
|
50
|
+
## Storage
|
51
|
+
|
52
|
+
By default, rack-mini-profiler stores its results in a memory store:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
# our default
|
56
|
+
Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
|
57
|
+
```
|
58
|
+
|
59
|
+
There are 2 other available storage engines, `RedisStore` and `FileStore`.
|
60
|
+
|
61
|
+
MemoryStore is stores results in a processes heap - something that does not work well in a multi process environment.
|
62
|
+
FileStore stores results in the file system - something that may not work well in a multi machine environment.
|
63
|
+
|
64
|
+
Additionally you may implement an AbstractStore for your own provider.
|
65
|
+
|
66
|
+
Rails hooks up a FileStore for all environments.
|
67
|
+
|
50
68
|
## Running the Specs
|
51
69
|
|
52
70
|
```
|
data/lib/html/includes.css
CHANGED
@@ -1 +1,75 @@
|
|
1
|
-
.profiler-result,.profiler-queries{color:#555;line-height:1;font-size:12px;}.profiler-result pre,.profiler-queries pre,.profiler-result code,.profiler-queries code,.profiler-result label,.profiler-queries label,.profiler-result table,.profiler-queries table,.profiler-result tbody,.profiler-queries tbody,.profiler-result thead,.profiler-queries thead,.profiler-result tfoot,.profiler-queries tfoot,.profiler-result tr,.profiler-queries tr,.profiler-result th,.profiler-queries th,.profiler-result td,.profiler-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}.profiler-result table,.profiler-queries table{border-collapse:collapse;border-spacing:0;}.profiler-result a,.profiler-queries a,.profiler-result a:hover,.profiler-queries a:hover{cursor:pointer;color:#07c;}.profiler-result a,.profiler-queries a{text-decoration:none;}.profiler-result a:hover,.profiler-queries a:hover{text-decoration:underline;}.profiler-result{font-family:Helvetica,Arial,sans-serif;}.profiler-result .profiler-toggle-duration-with-children{float:right;}.profiler-result table.profiler-client-timings{margin-top:10px;}.profiler-result .profiler-label{color:#555;overflow:hidden;text-overflow:ellipsis;}.profiler-result .profiler-unit{color:#aaa;}.profiler-result .profiler-trivial{display:none;}.profiler-result .profiler-trivial td,.profiler-result .profiler-trivial td *{color:#aaa !important;}.profiler-result pre,.profiler-result code,.profiler-result .profiler-number,.profiler-result .profiler-unit{font-family:Consolas,monospace,serif;}.profiler-result .profiler-number{color:#111;}.profiler-result .profiler-info{text-align:right;}.profiler-result .profiler-info .profiler-name{float:left;}.profiler-result .profiler-info .profiler-server-time{white-space:nowrap;}.profiler-result .profiler-timings th{background-color:#fff;color:#aaa;text-align:right;}.profiler-result .profiler-timings th,.profiler-result .profiler-timings td{white-space:nowrap;}.profiler-result .profiler-timings .profiler-duration-with-children{display:none;}.profiler-result .profiler-timings .profiler-duration{font-family:Consolas,monospace,serif;color:#111;text-align:right;}.profiler-result .profiler-timings .profiler-indent{letter-spacing:4px;}.profiler-result .profiler-timings .profiler-queries-show .profiler-number,.profiler-result .profiler-timings .profiler-queries-show .profiler-unit{color:#07c;}.profiler-result .profiler-timings .profiler-queries-duration{padding-left:6px;}.profiler-result .profiler-timings .profiler-percent-in-sql{white-space:nowrap;text-align:right;}.profiler-result .profiler-timings tfoot td{padding-top:10px;text-align:right;}.profiler-result .profiler-timings tfoot td a{font-size:95%;display:inline-block;margin-left:12px;}.profiler-result .profiler-timings tfoot td a:first-child{float:left;margin-left:0px;}.profiler-result .profiler-queries{font-family:Helvetica,Arial,sans-serif;}.profiler-result .profiler-queries .profiler-stack-trace{margin-bottom:15px;}.profiler-result .profiler-queries pre{font-family:Consolas,monospace,serif;white-space:pre-wrap;}.profiler-result .profiler-queries th{background-color:#fff;border-bottom:1px solid #555;font-weight:bold;padding:15px;white-space:nowrap;}.profiler-result .profiler-queries td{padding:15px;text-align:left;background-color:#fff;}.profiler-result .profiler-queries td:last-child{padding-right:25px;}.profiler-result .profiler-queries .profiler-odd td{background-color:#e5e5e5;}.profiler-result .profiler-queries .profiler-since-start,.profiler-result .profiler-queries .profiler-duration{text-align:right;}.profiler-result .profiler-queries .profiler-info div{text-align:right;margin-bottom:5px;}.profiler-result .profiler-queries .profiler-gap-info,.profiler-result .profiler-queries .profiler-gap-info td{background-color:#ccc;}.profiler-result .profiler-queries .profiler-gap-info .profiler-unit{color:#777;}.profiler-result .profiler-queries .profiler-gap-info .profiler-info{text-align:right;}.profiler-result .profiler-queries .profiler-gap-info.profiler-trivial-gaps{display:none;}.profiler-result .profiler-queries .profiler-trivial-gap-container{text-align:center;}.profiler-result .profiler-queries .str{color:maroon;}.profiler-result .profiler-queries .kwd{color:#00008b;}.profiler-result .profiler-queries .com{color:gray;}.profiler-result .profiler-queries .typ{color:#2b91af;}.profiler-result .profiler-queries .lit{color:maroon;}.profiler-result .profiler-queries .pun{color:#000;}.profiler-result .profiler-queries .pln{color:#000;}.profiler-result .profiler-queries .tag{color:maroon;}.profiler-result .profiler-queries .atn{color:red;}.profiler-result .profiler-queries .atv{color:blue;}.profiler-result .profiler-queries .dec{color:purple;}.profiler-result .profiler-warning,.profiler-result .profiler-warning *,.profiler-result .profiler-warning .profiler-queries-show,.profiler-result .profiler-warning .profiler-queries-show .profiler-unit{color:#f00;}.profiler-result .profiler-warning:hover,.profiler-result .profiler-warning *:hover,.profiler-result .profiler-warning .profiler-queries-show:hover,.profiler-result .profiler-warning .profiler-queries-show .profiler-unit:hover{color:#f00;}.profiler-result .profiler-nuclear{color:#f00;font-weight:bold;padding-right:2px;}.profiler-result .profiler-nuclear:hover{color:#f00;}.profiler-results{z-index:2147483643;position:fixed;top:0px;}.profiler-results.profiler-left{left:0px;}.profiler-results.profiler-left.profiler-no-controls .profiler-result:last-child .profiler-button,.profiler-results.profiler-left .profiler-controls{-webkit-border-bottom-right-radius:10px;-moz-border-radius-bottomright:10px;border-bottom-right-radius:10px;}.profiler-results.profiler-left .profiler-button,.profiler-results.profiler-left .profiler-controls{border-right:1px solid #888;}.profiler-results.profiler-right{right:0px;}.profiler-results.profiler-right.profiler-no-controls .profiler-result:last-child .profiler-button,.profiler-results.profiler-right .profiler-controls{-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomleft:10px;border-bottom-left-radius:10px;}.profiler-results.profiler-right .profiler-button,.profiler-results.profiler-right .profiler-controls{border-left:1px solid #888;}.profiler-results .profiler-button,.profiler-results .profiler-controls{display:none;z-index:2147483640;border-bottom:1px solid #888;background-color:#fff;padding:4px 7px;text-align:right;cursor:pointer;}.profiler-results .profiler-button.profiler-button-active,.profiler-results .profiler-controls.profiler-button-active{background-color:maroon;}.profiler-results .profiler-button.profiler-button-active .profiler-number,.profiler-results .profiler-controls.profiler-button-active .profiler-number,.profiler-results .profiler-button.profiler-button-active .profiler-nuclear,.profiler-results .profiler-controls.profiler-button-active .profiler-nuclear{color:#fff;font-weight:bold;}.profiler-results .profiler-button.profiler-button-active .profiler-unit,.profiler-results .profiler-controls.profiler-button-active .profiler-unit{color:#fff;font-weight:normal;}.profiler-results .profiler-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.profiler-results .profiler-controls span{border-right:1px solid #aaa;padding-right:5px;margin-right:5px;cursor:pointer;}.profiler-results .profiler-controls span:last-child{border-right:none;}.profiler-results .profiler-popup{display:none;z-index:2147483641;position:absolute;background-color:#fff;border:1px solid #aaa;padding:5px 10px;text-align:left;line-height:18px;overflow:auto;-moz-box-shadow:0px 1px 15px #555;-webkit-box-shadow:0px 1px 15px #555;box-shadow:0px 1px 15px #555;}.profiler-results .profiler-popup .profiler-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid #ddd;}.profiler-results .profiler-popup .profiler-info .profiler-name{font-size:110%;font-weight:bold;}.profiler-results .profiler-popup .profiler-info .profiler-name .profiler-overall-duration{display:none;}.profiler-results .profiler-popup .profiler-info .profiler-server-time{font-size:95%;}.profiler-results .profiler-popup .profiler-timings th,.profiler-results .profiler-popup .profiler-timings td{padding-left:6px;padding-right:6px;}.profiler-results .profiler-popup .profiler-timings th{font-size:95%;padding-bottom:3px;}.profiler-results .profiler-popup .profiler-timings .profiler-label{max-width:275px;}.profiler-results .profiler-queries{display:none;z-index:2147483643;position:absolute;overflow-y:auto;overflow-x:hidden;background-color:#fff;}.profiler-results .profiler-queries th{font-size:17px;}.profiler-results.profiler-min .profiler-result{display:none;}.profiler-results.profiler-min .profiler-controls span{display:none;}.profiler-results.profiler-min .profiler-controls .profiler-min-max{border-right:none;padding:0px;margin:0px;}.profiler-queries-bg{z-index:2147483642;display:none;background:#000;opacity:0.7;position:absolute;top:0px;left:0px;min-width:100%;}.profiler-result-full .profiler-result{width:950px;margin:30px auto;}.profiler-result-full .profiler-result .profiler-button{display:none;}.profiler-result-full .profiler-result .profiler-popup .profiler-info{font-size:25px;border-bottom:1px solid #aaa;padding-bottom:3px;margin-bottom:25px;}.profiler-result-full .profiler-result .profiler-popup .profiler-info .profiler-overall-duration{padding-right:20px;font-size:80%;color:#888;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings td,.profiler-result-full .profiler-result .profiler-popup .profiler-timings th{padding-left:8px;padding-right:8px;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings th{padding-bottom:7px;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings td{font-size:14px;padding-bottom:4px;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings td:first-child{padding-left:10px;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings .profiler-label{max-width:550px;}.profiler-result-full .profiler-result .profiler-queries{margin:25px 0;}.profiler-result-full .profiler-result .profiler-queries table{width:100%;}.profiler-result-full .profiler-result .profiler-queries th{font-size:16px;color:#555;line-height:20px;}.profiler-result-full .profiler-result .profiler-queries td{padding:15px 10px;text-align:left;}.profiler-result-full .profiler-result .profiler-queries .profiler-info div{text-align:right;margin-bottom:5px;}
|
1
|
+
.profiler-result,.profiler-queries{color:#555;line-height:1;font-size:12px;}.profiler-result pre,.profiler-queries pre,.profiler-result code,.profiler-queries code,.profiler-result label,.profiler-queries label,.profiler-result table,.profiler-queries table,.profiler-result tbody,.profiler-queries tbody,.profiler-result thead,.profiler-queries thead,.profiler-result tfoot,.profiler-queries tfoot,.profiler-result tr,.profiler-queries tr,.profiler-result th,.profiler-queries th,.profiler-result td,.profiler-queries td{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;background-color:transparent;overflow:visible;max-height:none;}
|
2
|
+
.profiler-result table,.profiler-queries table{border-collapse:collapse;border-spacing:0;}
|
3
|
+
.profiler-result a,.profiler-queries a,.profiler-result a:hover,.profiler-queries a:hover{cursor:pointer;color:#0077cc;}
|
4
|
+
.profiler-result a,.profiler-queries a{text-decoration:none;}.profiler-result a:hover,.profiler-queries a:hover{text-decoration:underline;}
|
5
|
+
.profiler-result{font-family:Helvetica,Arial,sans-serif;}.profiler-result .profiler-toggle-duration-with-children{float:right;}
|
6
|
+
.profiler-result table.profiler-client-timings{margin-top:10px;}
|
7
|
+
.profiler-result .profiler-label{color:#555555;overflow:hidden;text-overflow:ellipsis;}
|
8
|
+
.profiler-result .profiler-unit{color:#aaaaaa;}
|
9
|
+
.profiler-result .profiler-trivial{display:none;}.profiler-result .profiler-trivial td,.profiler-result .profiler-trivial td *{color:#aaaaaa !important;}
|
10
|
+
.profiler-result pre,.profiler-result code,.profiler-result .profiler-number,.profiler-result .profiler-unit{font-family:Consolas,monospace,serif;}
|
11
|
+
.profiler-result .profiler-number{color:#111111;}
|
12
|
+
.profiler-result .profiler-info{text-align:right;}.profiler-result .profiler-info .profiler-name{float:left;}
|
13
|
+
.profiler-result .profiler-info .profiler-server-time{white-space:nowrap;}
|
14
|
+
.profiler-result .profiler-timings th{background-color:#fff;color:#aaaaaa;text-align:right;}
|
15
|
+
.profiler-result .profiler-timings th,.profiler-result .profiler-timings td{white-space:nowrap;}
|
16
|
+
.profiler-result .profiler-timings .profiler-duration-with-children{display:none;}
|
17
|
+
.profiler-result .profiler-timings .profiler-duration{font-family:Consolas,monospace,serif;color:#111111;text-align:right;}
|
18
|
+
.profiler-result .profiler-timings .profiler-indent{letter-spacing:4px;}
|
19
|
+
.profiler-result .profiler-timings .profiler-queries-show .profiler-number,.profiler-result .profiler-timings .profiler-queries-show .profiler-unit{color:#0077cc;}
|
20
|
+
.profiler-result .profiler-timings .profiler-queries-duration{padding-left:6px;}
|
21
|
+
.profiler-result .profiler-timings .profiler-percent-in-sql{white-space:nowrap;text-align:right;}
|
22
|
+
.profiler-result .profiler-timings tfoot td{padding-top:10px;text-align:right;}.profiler-result .profiler-timings tfoot td a{font-size:95%;display:inline-block;margin-left:12px;}.profiler-result .profiler-timings tfoot td a:first-child{float:left;margin-left:0px;}
|
23
|
+
.profiler-result .profiler-queries{font-family:Helvetica,Arial,sans-serif;}.profiler-result .profiler-queries .profiler-stack-trace{margin-bottom:15px;}
|
24
|
+
.profiler-result .profiler-queries pre{font-family:Consolas,monospace,serif;white-space:pre-wrap;}
|
25
|
+
.profiler-result .profiler-queries th{background-color:#fff;border-bottom:1px solid #555;font-weight:bold;padding:15px;white-space:nowrap;}
|
26
|
+
.profiler-result .profiler-queries td{padding:15px;text-align:left;background-color:#fff;}.profiler-result .profiler-queries td:last-child{padding-right:25px;}
|
27
|
+
.profiler-result .profiler-queries .profiler-odd td{background-color:#e5e5e5;}
|
28
|
+
.profiler-result .profiler-queries .profiler-since-start,.profiler-result .profiler-queries .profiler-duration{text-align:right;}
|
29
|
+
.profiler-result .profiler-queries .profiler-info div{text-align:right;margin-bottom:5px;}
|
30
|
+
.profiler-result .profiler-queries .profiler-gap-info,.profiler-result .profiler-queries .profiler-gap-info td{background-color:#ccc;}
|
31
|
+
.profiler-result .profiler-queries .profiler-gap-info .profiler-unit{color:#777;}
|
32
|
+
.profiler-result .profiler-queries .profiler-gap-info .profiler-info{text-align:right;}
|
33
|
+
.profiler-result .profiler-queries .profiler-gap-info.profiler-trivial-gaps{display:none;}
|
34
|
+
.profiler-result .profiler-queries .profiler-trivial-gap-container{text-align:center;}
|
35
|
+
.profiler-result .profiler-queries .str{color:#800000;}
|
36
|
+
.profiler-result .profiler-queries .kwd{color:#00008b;}
|
37
|
+
.profiler-result .profiler-queries .com{color:#808080;}
|
38
|
+
.profiler-result .profiler-queries .typ{color:#2b91af;}
|
39
|
+
.profiler-result .profiler-queries .lit{color:#800000;}
|
40
|
+
.profiler-result .profiler-queries .pun{color:#000000;}
|
41
|
+
.profiler-result .profiler-queries .pln{color:#000000;}
|
42
|
+
.profiler-result .profiler-queries .tag{color:#800000;}
|
43
|
+
.profiler-result .profiler-queries .atn{color:#ff0000;}
|
44
|
+
.profiler-result .profiler-queries .atv{color:#0000ff;}
|
45
|
+
.profiler-result .profiler-queries .dec{color:#800080;}
|
46
|
+
.profiler-result .profiler-warning,.profiler-result .profiler-warning *,.profiler-result .profiler-warning .profiler-queries-show,.profiler-result .profiler-warning .profiler-queries-show .profiler-unit{color:#f00;}.profiler-result .profiler-warning:hover,.profiler-result .profiler-warning *:hover,.profiler-result .profiler-warning .profiler-queries-show:hover,.profiler-result .profiler-warning .profiler-queries-show .profiler-unit:hover{color:#f00;}
|
47
|
+
.profiler-result .profiler-nuclear{color:#f00;font-weight:bold;padding-right:2px;}.profiler-result .profiler-nuclear:hover{color:#f00;}
|
48
|
+
.profiler-results{z-index:2147483643;position:fixed;top:0px;}.profiler-results.profiler-left{left:0px;}.profiler-results.profiler-left.profiler-no-controls .profiler-result:last-child .profiler-button,.profiler-results.profiler-left .profiler-controls{-webkit-border-bottom-right-radius:10px;-moz-border-radius-bottomright:10px;border-bottom-right-radius:10px;}
|
49
|
+
.profiler-results.profiler-left .profiler-button,.profiler-results.profiler-left .profiler-controls{border-right:1px solid #888888;}
|
50
|
+
.profiler-results.profiler-right{right:0px;}.profiler-results.profiler-right.profiler-no-controls .profiler-result:last-child .profiler-button,.profiler-results.profiler-right .profiler-controls{-webkit-border-bottom-left-radius:10px;-moz-border-radius-bottomleft:10px;border-bottom-left-radius:10px;}
|
51
|
+
.profiler-results.profiler-right .profiler-button,.profiler-results.profiler-right .profiler-controls{border-left:1px solid #888888;}
|
52
|
+
.profiler-results .profiler-button,.profiler-results .profiler-controls{display:none;z-index:2147483640;border-bottom:1px solid #888888;background-color:#fff;padding:4px 7px;text-align:right;cursor:pointer;}.profiler-results .profiler-button.profiler-button-active,.profiler-results .profiler-controls.profiler-button-active{background-color:maroon;}.profiler-results .profiler-button.profiler-button-active .profiler-number,.profiler-results .profiler-controls.profiler-button-active .profiler-number,.profiler-results .profiler-button.profiler-button-active .profiler-nuclear,.profiler-results .profiler-controls.profiler-button-active .profiler-nuclear{color:#fff;font-weight:bold;}
|
53
|
+
.profiler-results .profiler-button.profiler-button-active .profiler-unit,.profiler-results .profiler-controls.profiler-button-active .profiler-unit{color:#fff;font-weight:normal;}
|
54
|
+
.profiler-results .profiler-controls{display:block;font-size:12px;font-family:Consolas,monospace,serif;cursor:default;text-align:center;}.profiler-results .profiler-controls span{border-right:1px solid #aaaaaa;padding-right:5px;margin-right:5px;cursor:pointer;}
|
55
|
+
.profiler-results .profiler-controls span:last-child{border-right:none;}
|
56
|
+
.profiler-results .profiler-popup{display:none;z-index:2147483641;position:absolute;background-color:#fff;border:1px solid #aaa;padding:5px 10px;text-align:left;line-height:18px;overflow:auto;-moz-box-shadow:0px 1px 15px #555555;-webkit-box-shadow:0px 1px 15px #555555;box-shadow:0px 1px 15px #555555;}.profiler-results .profiler-popup .profiler-info{margin-bottom:3px;padding-bottom:2px;border-bottom:1px solid #ddd;}.profiler-results .profiler-popup .profiler-info .profiler-name{font-size:110%;font-weight:bold;}.profiler-results .profiler-popup .profiler-info .profiler-name .profiler-overall-duration{display:none;}
|
57
|
+
.profiler-results .profiler-popup .profiler-info .profiler-server-time{font-size:95%;}
|
58
|
+
.profiler-results .profiler-popup .profiler-timings th,.profiler-results .profiler-popup .profiler-timings td{padding-left:6px;padding-right:6px;}
|
59
|
+
.profiler-results .profiler-popup .profiler-timings th{font-size:95%;padding-bottom:3px;}
|
60
|
+
.profiler-results .profiler-popup .profiler-timings .profiler-label{max-width:275px;}
|
61
|
+
.profiler-results .profiler-queries{display:none;z-index:2147483643;position:absolute;overflow-y:auto;overflow-x:hidden;background-color:#fff;}.profiler-results .profiler-queries th{font-size:17px;}
|
62
|
+
.profiler-results.profiler-min .profiler-result{display:none;}
|
63
|
+
.profiler-results.profiler-min .profiler-controls span{display:none;}
|
64
|
+
.profiler-results.profiler-min .profiler-controls .profiler-min-max{border-right:none;padding:0px;margin:0px;}
|
65
|
+
.profiler-queries-bg{z-index:2147483642;display:none;background:#000;opacity:0.7;position:absolute;top:0px;left:0px;min-width:100%;}
|
66
|
+
.profiler-result-full .profiler-result{width:950px;margin:30px auto;}.profiler-result-full .profiler-result .profiler-button{display:none;}
|
67
|
+
.profiler-result-full .profiler-result .profiler-popup .profiler-info{font-size:25px;border-bottom:1px solid #aaaaaa;padding-bottom:3px;margin-bottom:25px;}.profiler-result-full .profiler-result .profiler-popup .profiler-info .profiler-overall-duration{padding-right:20px;font-size:80%;color:#888;}
|
68
|
+
.profiler-result-full .profiler-result .profiler-popup .profiler-timings td,.profiler-result-full .profiler-result .profiler-popup .profiler-timings th{padding-left:8px;padding-right:8px;}
|
69
|
+
.profiler-result-full .profiler-result .profiler-popup .profiler-timings th{padding-bottom:7px;}
|
70
|
+
.profiler-result-full .profiler-result .profiler-popup .profiler-timings td{font-size:14px;padding-bottom:4px;}.profiler-result-full .profiler-result .profiler-popup .profiler-timings td:first-child{padding-left:10px;}
|
71
|
+
.profiler-result-full .profiler-result .profiler-popup .profiler-timings .profiler-label{max-width:550px;}
|
72
|
+
.profiler-result-full .profiler-result .profiler-queries{margin:25px 0;}.profiler-result-full .profiler-result .profiler-queries table{width:100%;}
|
73
|
+
.profiler-result-full .profiler-result .profiler-queries th{font-size:16px;color:#555;line-height:20px;}
|
74
|
+
.profiler-result-full .profiler-result .profiler-queries td{padding:15px 10px;text-align:left;}
|
75
|
+
.profiler-result-full .profiler-result .profiler-queries .profiler-info div{text-align:right;margin-bottom:5px;}
|
data/lib/html/includes.js
CHANGED
@@ -100,6 +100,18 @@ var MiniProfiler = (function ($) {
|
|
100
100
|
copy.navigation.redirectCount = clientPerformance.navigation.redirectCount;
|
101
101
|
}
|
102
102
|
clientPerformance = copy;
|
103
|
+
|
104
|
+
// hack to add chrome timings
|
105
|
+
if (window.chrome && window.chrome.loadTimes) {
|
106
|
+
var chromeTimes = window.chrome.loadTimes();
|
107
|
+
if (chromeTimes.firstPaintTime) {
|
108
|
+
clientPerformance.timing["First Paint Time"] = Math.round(chromeTimes.firstPaintTime * 1000);
|
109
|
+
}
|
110
|
+
if (chromeTimes.firstPaintTime) {
|
111
|
+
clientPerformance.timing["First Paint After Load Time"] = Math.round(chromeTimes.firstPaintAfterLoadTime * 1000);
|
112
|
+
}
|
113
|
+
|
114
|
+
}
|
103
115
|
}
|
104
116
|
}
|
105
117
|
|
@@ -593,7 +605,7 @@ var MiniProfiler = (function ($) {
|
|
593
605
|
|
594
606
|
for (var i = 0; i < clientTimings.Timings.length; i++) {
|
595
607
|
t = clientTimings.Timings[i];
|
596
|
-
var trivial = t.Name != "Dom Complete" && t.Name != "Response";
|
608
|
+
var trivial = t.Name != "Dom Complete" && t.Name != "Response" && t.Name != "First Paint Time";
|
597
609
|
trivial = t.Duration < 2 ? trivial : false;
|
598
610
|
list.push(
|
599
611
|
{
|
@@ -811,4 +823,4 @@ PR_TAG:"tag",PR_TYPE:S}})()
|
|
811
823
|
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xA0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^\"\\]|\\.)*"|'(?:[^\'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\r\n]*|\/\*[\s\S]*?(?:\*\/|$))/],["kwd",/^(?: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|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|VALUES|VARYING|VIEW|WAITFOR|WHEN|WHERE|WHILE|WITH|WRITETEXT)(?=[^\w-]|$)/i,
|
812
824
|
null],["lit",/^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i],["pln",/^[a-z_][\w-]*/i],["pun",/^[^\w\t\n\r \xA0\"\'][^\w\t\n\r \xA0+\-\"\']*/]]),["sql"])
|
813
825
|
|
814
|
-
;
|
826
|
+
;
|
data/lib/html/includes.less
CHANGED
data/lib/html/profile_handler.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
<script type="text/javascript">
|
1
|
+
<script type="text/javascript">
|
2
2
|
(function(){{
|
3
|
-
var init = function() {{
|
3
|
+
var init = function() {{
|
4
4
|
var load = function(s,f){{
|
5
5
|
var sc = document.createElement('script');
|
6
6
|
sc.async = 'async';
|
@@ -14,8 +14,8 @@
|
|
14
14
|
}};
|
15
15
|
|
16
16
|
document.getElementsByTagName('head')[0].appendChild(sc);
|
17
|
-
}};
|
18
|
-
|
17
|
+
}};
|
18
|
+
|
19
19
|
var initMp = function(){{
|
20
20
|
load('{path}includes.js?v={version}',function(){{
|
21
21
|
MiniProfiler.init({{
|
@@ -32,18 +32,18 @@
|
|
32
32
|
}});
|
33
33
|
}});
|
34
34
|
}};
|
35
|
-
if ({useExistingjQuery}) {{
|
35
|
+
if ({useExistingjQuery} && typeof(jQuery) === 'function') {{
|
36
36
|
jQueryMP = jQuery;
|
37
37
|
initMp();
|
38
38
|
}} else {{
|
39
39
|
load('{path}jquery.1.7.1.js?v={version}', initMp);
|
40
40
|
}}
|
41
|
-
|
41
|
+
|
42
42
|
}};
|
43
43
|
|
44
|
-
var w = 0;
|
44
|
+
var w = 0;
|
45
45
|
var f = false;
|
46
|
-
var deferInit = function(){{
|
46
|
+
var deferInit = function(){{
|
47
47
|
if (f) return;
|
48
48
|
if (window.performance && window.performance.timing && window.performance.timing.loadEventEnd == 0 && w < 10000){{
|
49
49
|
setTimeout(deferInit, 100);
|
@@ -59,4 +59,4 @@
|
|
59
59
|
var o = window.onload;
|
60
60
|
window.onload = function(){{if(o)o; deferInit()}};
|
61
61
|
}})();
|
62
|
-
</script>
|
62
|
+
</script>
|
@@ -6,11 +6,24 @@ module Rack
|
|
6
6
|
# This class holds the client timings
|
7
7
|
class ClientTimerStruct < TimerStruct
|
8
8
|
|
9
|
+
def self.init_instrumentation
|
10
|
+
"<script type=\"text/javascript\">mPt=function(){var t=[];return{t:t,probe:function(n){t.push({d:new Date(),n:n})}}}()</script>"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.instrument(name,orig)
|
14
|
+
probe = "<script>mPt.probe('#{name}')</script>"
|
15
|
+
wrapped = probe
|
16
|
+
wrapped << orig
|
17
|
+
wrapped << probe
|
18
|
+
wrapped
|
19
|
+
end
|
20
|
+
|
21
|
+
|
9
22
|
def initialize(env={})
|
10
23
|
super
|
11
24
|
end
|
12
25
|
|
13
|
-
def init_from_form_data(env, page_struct)
|
26
|
+
def self.init_from_form_data(env, page_struct)
|
14
27
|
timings = []
|
15
28
|
clientTimes, clientPerf, baseTime = nil
|
16
29
|
form = env['rack.request.form_hash']
|
@@ -21,6 +34,26 @@ module Rack
|
|
21
34
|
baseTime = clientTimes['navigationStart'].to_i if clientTimes
|
22
35
|
return unless clientTimes && baseTime
|
23
36
|
|
37
|
+
probes = form['clientProbes']
|
38
|
+
translated = {}
|
39
|
+
if probes && probes != "null"
|
40
|
+
probes.each do |id, val|
|
41
|
+
name = val["n"]
|
42
|
+
translated[name] ||= {}
|
43
|
+
if translated[name][:start]
|
44
|
+
translated[name][:finish] = val["d"]
|
45
|
+
else
|
46
|
+
translated[name][:start] = val["d"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
translated.each do |name, data|
|
52
|
+
h = {"Name" => name, "Start" => data[:start].to_i - baseTime}
|
53
|
+
h["Duration"] = data[:finish].to_i - data[:start].to_i if data[:finish]
|
54
|
+
timings.push(h)
|
55
|
+
end
|
56
|
+
|
24
57
|
clientTimes.keys.find_all{|k| k =~ /Start$/ }.each do |k|
|
25
58
|
start = clientTimes[k].to_i - baseTime
|
26
59
|
finish = clientTimes[k.sub(/Start$/, "End")].to_i - baseTime
|
@@ -34,8 +67,10 @@ module Rack
|
|
34
67
|
timings.push("Name" => k, "Start" => clientTimes[k].to_i - baseTime, "Duration" => -1)
|
35
68
|
end
|
36
69
|
|
37
|
-
|
38
|
-
|
70
|
+
rval = self.new
|
71
|
+
rval['RedirectCount'] = env['rack.request.form_hash']['clientPerformance']['navigation']['redirectCount']
|
72
|
+
rval['Timings'] = timings
|
73
|
+
rval
|
39
74
|
end
|
40
75
|
end
|
41
76
|
|
data/lib/mini_profiler/config.rb
CHANGED
@@ -14,7 +14,7 @@ module Rack
|
|
14
14
|
|
15
15
|
attr_accessor :auto_inject, :base_url_path, :pre_authorize_cb, :position,
|
16
16
|
:backtrace_remove, :backtrace_filter, :skip_schema_queries,
|
17
|
-
:storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode
|
17
|
+
:storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode, :use_existing_jquery
|
18
18
|
|
19
19
|
def self.default
|
20
20
|
new.instance_eval {
|
@@ -30,6 +30,7 @@ module Rack
|
|
30
30
|
@storage = MiniProfiler::MemoryStore
|
31
31
|
@user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
32
32
|
@authorization_mode = :allow_all
|
33
|
+
@use_existing_jquery = false
|
33
34
|
self
|
34
35
|
}
|
35
36
|
end
|
@@ -16,7 +16,7 @@ module Rack
|
|
16
16
|
"Level" => 0,
|
17
17
|
"User" => "unknown user",
|
18
18
|
"HasUserViewed" => false,
|
19
|
-
"ClientTimings" =>
|
19
|
+
"ClientTimings" => nil,
|
20
20
|
"DurationMilliseconds" => 0,
|
21
21
|
"HasTrivialTimings" => true,
|
22
22
|
"HasAllTrivialTimigs" => false,
|
@@ -35,15 +35,19 @@ module Rack
|
|
35
35
|
def duration_ms
|
36
36
|
@attributes['Root']['DurationMilliseconds']
|
37
37
|
end
|
38
|
+
|
39
|
+
def root
|
40
|
+
@attributes['Root']
|
41
|
+
end
|
38
42
|
|
39
43
|
def to_json(*a)
|
40
44
|
attribs = @attributes.merge(
|
41
45
|
"Started" => '/Date(%d)/' % @attributes['Started'],
|
42
46
|
"DurationMilliseconds" => @attributes['Root']['DurationMilliseconds']
|
43
47
|
)
|
44
|
-
::JSON.generate(attribs,
|
48
|
+
::JSON.generate(attribs, :max_nesting => 100)
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
48
52
|
end
|
49
|
-
end
|
53
|
+
end
|
@@ -6,54 +6,103 @@ require 'mini_profiler/page_timer_struct'
|
|
6
6
|
require 'mini_profiler/sql_timer_struct'
|
7
7
|
require 'mini_profiler/client_timer_struct'
|
8
8
|
require 'mini_profiler/request_timer_struct'
|
9
|
-
require 'mini_profiler/body_add_proxy'
|
10
9
|
require 'mini_profiler/storage/abstract_store'
|
11
10
|
require 'mini_profiler/storage/memory_store'
|
12
11
|
require 'mini_profiler/storage/redis_store'
|
13
12
|
require 'mini_profiler/storage/file_store'
|
14
13
|
require 'mini_profiler/config'
|
14
|
+
require 'mini_profiler/profiling_methods'
|
15
|
+
require 'mini_profiler/context'
|
15
16
|
|
16
17
|
module Rack
|
17
18
|
|
18
19
|
class MiniProfiler
|
19
20
|
|
20
|
-
VERSION = '
|
21
|
-
@@instance = nil
|
21
|
+
VERSION = '104'.freeze
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
class << self
|
24
|
+
|
25
|
+
include Rack::MiniProfiler::ProfilingMethods
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def generate_id
|
28
|
+
rand(36**20).to_s(36)
|
29
|
+
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
def reset_config
|
32
|
+
@config = Config.default
|
33
|
+
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
# So we can change the configuration if we want
|
36
|
+
def config
|
37
|
+
@config ||= Config.default
|
38
|
+
end
|
39
|
+
|
40
|
+
def share_template
|
41
|
+
return @share_template unless @share_template.nil?
|
42
|
+
@share_template = ::File.read(::File.expand_path("../html/share.html", ::File.dirname(__FILE__)))
|
43
|
+
end
|
44
|
+
|
45
|
+
def current
|
46
|
+
Thread.current[:mini_profiler_private]
|
47
|
+
end
|
48
|
+
|
49
|
+
def current=(c)
|
50
|
+
# we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
|
51
|
+
Thread.current[:mini_profiler_private]= c
|
52
|
+
end
|
53
|
+
|
54
|
+
# discard existing results, don't track this request
|
55
|
+
def discard_results
|
56
|
+
self.current.discard = true if current
|
57
|
+
end
|
58
|
+
|
59
|
+
# user has the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
60
|
+
def has_profiling_cookie?(env)
|
61
|
+
env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin=stylin")
|
62
|
+
end
|
63
|
+
|
64
|
+
# remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
65
|
+
def remove_profiling_cookie(headers)
|
66
|
+
Rack::Utils.delete_cookie_header!(headers, '__profilin')
|
67
|
+
end
|
39
68
|
|
40
|
-
|
41
|
-
|
42
|
-
|
69
|
+
def set_profiling_cookie(headers)
|
70
|
+
Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
|
71
|
+
end
|
72
|
+
|
73
|
+
def create_current(env={}, options={})
|
74
|
+
# profiling the request
|
75
|
+
self.current = Context.new
|
76
|
+
self.current.inject_js = config.auto_inject && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
|
77
|
+
self.current.page_struct = PageTimerStruct.new(env)
|
78
|
+
self.current.current_timer = current.page_struct['Root']
|
79
|
+
end
|
80
|
+
|
81
|
+
def authorize_request
|
82
|
+
Thread.current[:mp_authorized] = true
|
83
|
+
end
|
84
|
+
|
85
|
+
def deauthorize_request
|
86
|
+
Thread.current[:mp_authorized] = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def request_authorized?
|
90
|
+
Thread.current[:mp_authorized]
|
91
|
+
end
|
43
92
|
end
|
44
93
|
|
45
94
|
#
|
46
95
|
# options:
|
47
96
|
# :auto_inject - should script be automatically injected on every html page (not xhr)
|
48
97
|
def initialize(app, config = nil)
|
49
|
-
@@instance = self
|
50
98
|
MiniProfiler.config.merge!(config)
|
51
99
|
@config = MiniProfiler.config
|
52
100
|
@app = app
|
53
101
|
@config.base_url_path << "/" unless @config.base_url_path.end_with? "/"
|
54
102
|
unless @config.storage_instance
|
55
|
-
@
|
103
|
+
@config.storage_instance = @config.storage.new(@config.storage_options)
|
56
104
|
end
|
105
|
+
@storage = @config.storage_instance
|
57
106
|
end
|
58
107
|
|
59
108
|
def user(env)
|
@@ -69,7 +118,7 @@ module Rack
|
|
69
118
|
return [404, {}, ["Request not found: #{request['id']} - user #{user(env)}"]]
|
70
119
|
end
|
71
120
|
unless page_struct['HasUserViewed']
|
72
|
-
|
121
|
+
page_struct['ClientTimings'] = ClientTimerStruct.init_from_form_data(env, page_struct)
|
73
122
|
page_struct['HasUserViewed'] = true
|
74
123
|
@storage.save(page_struct)
|
75
124
|
@storage.set_viewed(user(env), id)
|
@@ -102,18 +151,19 @@ module Rack
|
|
102
151
|
return [404, {}, ["Not found"]] unless ::File.exists? full_path
|
103
152
|
f = Rack::File.new nil
|
104
153
|
f.path = full_path
|
105
|
-
f.cache_control = "max-age:86400"
|
106
|
-
f.serving env
|
107
|
-
end
|
108
154
|
|
109
|
-
|
110
|
-
|
111
|
-
|
155
|
+
begin
|
156
|
+
f.cache_control = "max-age:86400"
|
157
|
+
f.serving env
|
158
|
+
rescue
|
159
|
+
# old versions of rack have a different api
|
160
|
+
status, headers, body = f.serving
|
161
|
+
headers.merge! 'Cache-Control' => "max-age:86400"
|
162
|
+
[status, headers, body]
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
112
166
|
|
113
|
-
def self.current=(c)
|
114
|
-
# we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
|
115
|
-
Thread.current['profiler.mini.private'] = c
|
116
|
-
end
|
117
167
|
|
118
168
|
def current
|
119
169
|
MiniProfiler.current
|
@@ -123,48 +173,11 @@ module Rack
|
|
123
173
|
MiniProfiler.current=c
|
124
174
|
end
|
125
175
|
|
126
|
-
# discard existing results, don't track this request
|
127
|
-
def self.discard_results
|
128
|
-
current[:discard] = true if current
|
129
|
-
end
|
130
|
-
|
131
|
-
# user has the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
132
|
-
def self.has_profiling_cookie?(env)
|
133
|
-
env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin=stylin")
|
134
|
-
end
|
135
|
-
|
136
|
-
# remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
137
|
-
def self.remove_profiling_cookie(headers)
|
138
|
-
Rack::Utils.delete_cookie_header!(headers, '__profilin')
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.set_profiling_cookie(headers)
|
142
|
-
Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
|
143
|
-
end
|
144
176
|
|
145
177
|
def config
|
146
178
|
@config
|
147
179
|
end
|
148
180
|
|
149
|
-
def self.create_current(env={}, options={})
|
150
|
-
# profiling the request
|
151
|
-
self.current = {}
|
152
|
-
self.current['inject_js'] = config.auto_inject && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
|
153
|
-
self.current['page_struct'] = PageTimerStruct.new(env)
|
154
|
-
self.current['current_timer'] = current['page_struct']['Root']
|
155
|
-
end
|
156
|
-
|
157
|
-
def self.authorize_request
|
158
|
-
Thread.current[:mp_authorized] = true
|
159
|
-
end
|
160
|
-
|
161
|
-
def self.deauthorize_request
|
162
|
-
Thread.current[:mp_authorized] = nil
|
163
|
-
end
|
164
|
-
|
165
|
-
def self.request_authorized?
|
166
|
-
Thread.current[:mp_authorized]
|
167
|
-
end
|
168
181
|
|
169
182
|
def call(env)
|
170
183
|
status = headers = body = nil
|
@@ -174,12 +187,12 @@ module Rack
|
|
174
187
|
(@config.skip_paths && @config.skip_paths.any?{ |p| path[0,p.length] == p}) ||
|
175
188
|
env["QUERY_STRING"] =~ /pp=skip/
|
176
189
|
|
177
|
-
has_profiling_cookie =
|
190
|
+
has_profiling_cookie = MiniProfiler.has_profiling_cookie?(env)
|
178
191
|
|
179
192
|
if skip_it || (@config.authorization_mode == :whitelist && !has_profiling_cookie)
|
180
193
|
status,headers,body = @app.call(env)
|
181
194
|
if !skip_it && @config.authorization_mode == :whitelist && !has_profiling_cookie && MiniProfiler.request_authorized?
|
182
|
-
|
195
|
+
MiniProfiler.set_profiling_cookie(headers)
|
183
196
|
end
|
184
197
|
return [status,headers,body]
|
185
198
|
end
|
@@ -188,34 +201,38 @@ module Rack
|
|
188
201
|
return serve_html(env) if env['PATH_INFO'].start_with? @config.base_url_path
|
189
202
|
|
190
203
|
MiniProfiler.create_current(env, @config)
|
191
|
-
|
192
204
|
MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
|
193
205
|
if env["QUERY_STRING"] =~ /pp=no-backtrace/
|
194
|
-
current
|
206
|
+
current.skip_backtrace = true
|
195
207
|
elsif env["QUERY_STRING"] =~ /pp=full-backtrace/
|
196
|
-
current
|
208
|
+
current.full_backtrace = true
|
197
209
|
end
|
198
210
|
|
199
211
|
done_sampling = false
|
200
212
|
quit_sampler = false
|
201
213
|
backtraces = nil
|
214
|
+
missing_stacktrace = false
|
202
215
|
if env["QUERY_STRING"] =~ /pp=sample/
|
203
216
|
backtraces = []
|
204
217
|
t = Thread.current
|
205
218
|
Thread.new {
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
i
|
215
|
-
|
216
|
-
|
219
|
+
begin
|
220
|
+
require 'stacktrace' rescue nil
|
221
|
+
if !t.respond_to? :stacktrace
|
222
|
+
missing_stacktrace = true
|
223
|
+
quit_sampler = true
|
224
|
+
return
|
225
|
+
end
|
226
|
+
i = 10000 # for sanity never grab more than 10k samples
|
227
|
+
while i > 0
|
228
|
+
break if done_sampling
|
229
|
+
i -= 1
|
230
|
+
backtraces << t.stacktrace
|
231
|
+
sleep 0.001
|
232
|
+
end
|
233
|
+
ensure
|
234
|
+
quit_sampler = true
|
217
235
|
end
|
218
|
-
quit_sampler = true
|
219
236
|
}
|
220
237
|
end
|
221
238
|
|
@@ -230,14 +247,14 @@ module Rack
|
|
230
247
|
end
|
231
248
|
end
|
232
249
|
|
233
|
-
skip_it = current
|
250
|
+
skip_it = current.discard
|
234
251
|
if (config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
|
235
252
|
MiniProfiler.remove_profiling_cookie(headers)
|
236
253
|
skip_it = true
|
237
254
|
end
|
238
255
|
|
239
256
|
return [status,headers,body] if skip_it
|
240
|
-
|
257
|
+
|
241
258
|
# we must do this here, otherwise current[:discard] is not being properly treated
|
242
259
|
if env["QUERY_STRING"] =~ /pp=env/
|
243
260
|
body.close if body.respond_to? :close
|
@@ -249,11 +266,12 @@ module Rack
|
|
249
266
|
return help
|
250
267
|
end
|
251
268
|
|
252
|
-
page_struct = current
|
269
|
+
page_struct = current.page_struct
|
253
270
|
page_struct['Root'].record_time((Time.now - start) * 1000)
|
254
271
|
|
255
272
|
if backtraces
|
256
273
|
body.close if body.respond_to? :close
|
274
|
+
return help(:stacktrace) if missing_stacktrace
|
257
275
|
return analyze(backtraces, page_struct)
|
258
276
|
end
|
259
277
|
|
@@ -265,30 +283,44 @@ module Rack
|
|
265
283
|
# inject headers, script
|
266
284
|
if status == 200
|
267
285
|
|
286
|
+
# mini profiler is meddling with stuff, we can not cache cause we will get incorrect data
|
287
|
+
# Rack::ETag has already inserted some nonesense in the chain
|
288
|
+
headers.delete('ETag')
|
289
|
+
headers.delete('Date')
|
290
|
+
headers['Cache-Control'] = 'must-revalidate, private, max-age=0'
|
291
|
+
|
268
292
|
# inject header
|
269
293
|
if headers.is_a? Hash
|
270
294
|
headers['X-MiniProfiler-Ids'] = ids_json(env)
|
271
295
|
end
|
272
296
|
|
273
297
|
# inject script
|
274
|
-
if current
|
298
|
+
if current.inject_js \
|
275
299
|
&& headers.has_key?('Content-Type') \
|
276
300
|
&& !headers['Content-Type'].match(/text\/html/).nil? then
|
277
|
-
|
301
|
+
|
302
|
+
response = Rack::Response.new([], status, headers)
|
303
|
+
script = self.get_profile_script(env)
|
304
|
+
if String === body
|
305
|
+
response.write inject(body,script)
|
306
|
+
else
|
307
|
+
body.each { |fragment| response.write inject(fragment, script) }
|
308
|
+
end
|
309
|
+
body.close if body.respond_to? :close
|
310
|
+
return response.finish
|
278
311
|
end
|
279
312
|
end
|
280
313
|
|
281
|
-
# mini profiler is meddling with stuff, we can not cache cause we will get incorrect data
|
282
|
-
# Rack::ETag has already inserted some nonesense in the chain
|
283
|
-
headers.delete('ETag')
|
284
|
-
headers.delete('Date')
|
285
|
-
headers['Cache-Control'] = 'must-revalidate, private, max-age=0'
|
286
314
|
[status, headers, body]
|
287
315
|
ensure
|
288
316
|
# Make sure this always happens
|
289
317
|
current = nil
|
290
318
|
end
|
291
319
|
|
320
|
+
def inject(fragment, script)
|
321
|
+
fragment.sub(/<\/body>/i, script + "</body>")
|
322
|
+
end
|
323
|
+
|
292
324
|
def dump_env(env)
|
293
325
|
headers = {'Content-Type' => 'text/plain'}
|
294
326
|
body = ""
|
@@ -298,7 +330,7 @@ module Rack
|
|
298
330
|
[200, headers, [body]]
|
299
331
|
end
|
300
332
|
|
301
|
-
def help
|
333
|
+
def help(category = nil)
|
302
334
|
headers = {'Content-Type' => 'text/plain'}
|
303
335
|
body = "Append the following to your query string:
|
304
336
|
|
@@ -309,24 +341,48 @@ module Rack
|
|
309
341
|
pp=full-backtrace : enable full backtrace for SQL executed
|
310
342
|
pp=sample : sample stack traces and return a report isolating heavy usage (requires the stacktrace gem)
|
311
343
|
"
|
312
|
-
|
344
|
+
if (category == :stacktrace)
|
345
|
+
body = "pp=stacktrace requires the stacktrace gem - add gem 'stacktrace' to your Gemfile"
|
346
|
+
end
|
347
|
+
|
313
348
|
[200, headers, [body]]
|
314
349
|
end
|
315
350
|
|
316
351
|
def analyze(traces, page_struct)
|
317
352
|
headers = {'Content-Type' => 'text/plain'}
|
318
353
|
body = "Collected: #{traces.count} stack traces. Duration(ms): #{page_struct.duration_ms}"
|
354
|
+
|
355
|
+
seen = {}
|
356
|
+
fulldump = ""
|
319
357
|
traces.each do |trace|
|
320
|
-
|
358
|
+
fulldump << "\n\n"
|
359
|
+
distinct = {}
|
321
360
|
trace.each do |frame|
|
322
|
-
|
361
|
+
name = "#{frame.klass} #{frame.method}"
|
362
|
+
unless distinct[name]
|
363
|
+
distinct[name] = true
|
364
|
+
seen[name] ||= 0
|
365
|
+
seen[name] += 1
|
366
|
+
end
|
367
|
+
fulldump << name << "\n"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
body << "\n\nStack Trace Analysis\n"
|
372
|
+
seen.to_a.sort{|x,y| y[1] <=> x[1]}.each do |name, count|
|
373
|
+
if count > traces.count / 10
|
374
|
+
body << "#{name} x #{count}\n"
|
323
375
|
end
|
324
376
|
end
|
377
|
+
|
378
|
+
body << "\n\n\nRaw traces \n"
|
379
|
+
body << fulldump
|
380
|
+
|
325
381
|
[200, headers, [body]]
|
326
382
|
end
|
327
383
|
|
328
384
|
def ids_json(env)
|
329
|
-
ids = [current
|
385
|
+
ids = [current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])
|
330
386
|
::JSON.generate(ids.uniq)
|
331
387
|
end
|
332
388
|
|
@@ -345,9 +401,9 @@ module Rack
|
|
345
401
|
showChildren = false
|
346
402
|
maxTracesToShow = 10
|
347
403
|
showControls = false
|
348
|
-
currentId = current
|
404
|
+
currentId = current.page_struct["Id"]
|
349
405
|
authorized = true
|
350
|
-
|
406
|
+
useExistingjQuery = @config.use_existing_jquery
|
351
407
|
# TODO : cache this snippet
|
352
408
|
script = IO.read(::File.expand_path('../html/profile_handler.js', ::File.dirname(__FILE__)))
|
353
409
|
# replace the variables
|
@@ -357,52 +413,13 @@ module Rack
|
|
357
413
|
end
|
358
414
|
# replace the '{{' and '}}''
|
359
415
|
script.gsub!(/\{\{/, '{').gsub!(/\}\}/, '}')
|
360
|
-
current
|
416
|
+
current.inject_js = false
|
361
417
|
script
|
362
418
|
end
|
363
419
|
|
364
420
|
# cancels automatic injection of profile script for the current page
|
365
421
|
def cancel_auto_inject(env)
|
366
|
-
current
|
367
|
-
end
|
368
|
-
|
369
|
-
# perform a profiling step on given block
|
370
|
-
def self.step(name)
|
371
|
-
if current
|
372
|
-
old_timer = current['current_timer']
|
373
|
-
new_step = RequestTimerStruct.new(name, current['page_struct'])
|
374
|
-
current['current_timer'] = new_step
|
375
|
-
new_step['Name'] = name
|
376
|
-
start = Time.now
|
377
|
-
result = yield if block_given?
|
378
|
-
new_step.record_time((Time.now - start)*1000)
|
379
|
-
old_timer.add_child(new_step)
|
380
|
-
current['current_timer'] = old_timer
|
381
|
-
result
|
382
|
-
else
|
383
|
-
yield if block_given?
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
def self.profile_method(klass, method, &blk)
|
388
|
-
default_name = klass.to_s + " " + method.to_s
|
389
|
-
with_profiling = (method.to_s + "_with_mini_profiler").intern
|
390
|
-
without_profiling = (method.to_s + "_without_mini_profiler").intern
|
391
|
-
|
392
|
-
klass.send :alias_method, without_profiling, method
|
393
|
-
klass.send :define_method, with_profiling do |*args, &orig|
|
394
|
-
name = default_name
|
395
|
-
name = blk.bind(self).call(*args) if blk
|
396
|
-
::Rack::MiniProfiler.step name do
|
397
|
-
self.send without_profiling, *args, &orig
|
398
|
-
end
|
399
|
-
end
|
400
|
-
klass.send :alias_method, method, with_profiling
|
401
|
-
end
|
402
|
-
|
403
|
-
def record_sql(query, elapsed_ms)
|
404
|
-
c = current
|
405
|
-
c['current_timer'].add_sql(query, elapsed_ms, c['page_struct'], c['skip-backtrace'], c['full-backtrace']) if (c && c['current_timer'])
|
422
|
+
current.inject_js = false
|
406
423
|
end
|
407
424
|
|
408
425
|
end
|