rack-mini-profiler 0.1.2 → 0.1.7
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 +26 -0
- data/README.md +17 -2
- data/lib/html/includes.css +75 -1
- data/lib/html/includes.js +14 -2
- data/lib/html/includes.less +1 -1
- data/lib/mini_profiler/client_timer_struct.rb +33 -0
- data/lib/mini_profiler/config.rb +3 -3
- data/lib/mini_profiler/context.rb +10 -0
- data/lib/mini_profiler/page_timer_struct.rb +6 -2
- data/lib/mini_profiler/profiler.rb +144 -131
- data/lib/mini_profiler/profiling_methods.rb +73 -0
- data/lib/mini_profiler/request_timer_struct.rb +40 -9
- data/lib/mini_profiler/sql_timer_struct.rb +15 -4
- data/lib/mini_profiler_rails/railtie.rb +44 -4
- data/lib/patches/sql_patches.rb +154 -34
- data/rack-mini-profiler.gemspec +2 -2
- metadata +7 -7
- data/CHANGELOG.md +0 -8
- data/lib/html/MiniProfilerHandler.cs +0 -419
- data/lib/html/share.html +0 -11
data/CHANGELOG
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
28-June-2012 - Sam
|
2
|
+
|
3
|
+
* Started change log
|
4
|
+
* Corrected profiler so it properly captures POST requests (was supressing non 200s)
|
5
|
+
* Amended Rack.MiniProfiler.config[:user_provider] to use ip addres for identity
|
6
|
+
* Fixed bug where unviewed missing ids never got cleared
|
7
|
+
* Supress all '/assets/' in the rails tie (makes debugging easier)
|
8
|
+
* record_sql was mega buggy
|
9
|
+
|
10
|
+
9-July-2012 - Sam
|
11
|
+
|
12
|
+
* Cleaned up mechanism for profiling in production, all you need to do now
|
13
|
+
is call Rack::MiniProfiler.authorize_request to get profiling working in
|
14
|
+
production
|
15
|
+
* Added option to display full backtraces pp=full-backtrace
|
16
|
+
* Cleaned up railties, got rid of the post authorize callback
|
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
|
+
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Middleware that displays speed badge for every html page. Designed to work both in production and in development.
|
4
4
|
|
5
|
-
## Using mini-profiler in your app
|
5
|
+
## Using rack-mini-profiler in your app
|
6
6
|
|
7
7
|
Install/add to Gemfile
|
8
8
|
|
@@ -13,6 +13,20 @@ Using Rails:
|
|
13
13
|
|
14
14
|
All you have to do is include the Gem and you're good to go in development.
|
15
15
|
|
16
|
+
rack-mini-profiler is designed with production profiling in mind. To enable that just run `Rack::MiniProfiler.authorize_request` once you know a request is allowed to profile.
|
17
|
+
|
18
|
+
For example:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# A hook in your ApplicationController
|
22
|
+
def authorize
|
23
|
+
if current_user.is_admin?
|
24
|
+
Rack::MiniProfiler.authorize_request
|
25
|
+
end
|
26
|
+
end
|
27
|
+
````
|
28
|
+
|
29
|
+
|
16
30
|
Using Builder:
|
17
31
|
|
18
32
|
```ruby
|
@@ -56,9 +70,10 @@ In a Rails app, this can be done conveniently in an initializer such as config/i
|
|
56
70
|
## Available Options
|
57
71
|
|
58
72
|
* 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.
|
59
|
-
* post_authorize_cb - A lambda that is called after your request executed to ensure you really have access to the results.
|
60
73
|
* position - Can either be 'right' or 'left'. Default is 'left'.
|
61
74
|
* 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.
|
62
75
|
|
76
|
+
## Special query strings
|
63
77
|
|
78
|
+
If you include the query string `pp=help` at the end of your request you will see the various option you have. You can use these options to extend or contract the amount of diagnostics rack-mini-profiler gathers.
|
64
79
|
|
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
@@ -6,6 +6,19 @@ 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
|
@@ -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
|
data/lib/mini_profiler/config.rb
CHANGED
@@ -12,9 +12,9 @@ module Rack
|
|
12
12
|
@attributes
|
13
13
|
end
|
14
14
|
|
15
|
-
attr_accessor :auto_inject, :base_url_path, :pre_authorize_cb, :
|
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
|
17
|
+
:storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode
|
18
18
|
|
19
19
|
def self.default
|
20
20
|
new.instance_eval {
|
@@ -25,11 +25,11 @@ module Rack
|
|
25
25
|
@pre_authorize_cb = lambda {|env| true}
|
26
26
|
|
27
27
|
# called after rack chain, to ensure we are REALLY allowed to profile
|
28
|
-
@post_authorize_cb = nil
|
29
28
|
@position = 'left' # Where it is displayed
|
30
29
|
@skip_schema_queries = false
|
31
30
|
@storage = MiniProfiler::MemoryStore
|
32
31
|
@user_provider = Proc.new{|env| Rack::Request.new(env).ip}
|
32
|
+
@authorization_mode = :allow_all
|
33
33
|
self
|
34
34
|
}
|
35
35
|
end
|
@@ -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
|
@@ -12,41 +12,90 @@ require 'mini_profiler/storage/memory_store'
|
|
12
12
|
require 'mini_profiler/storage/redis_store'
|
13
13
|
require 'mini_profiler/storage/file_store'
|
14
14
|
require 'mini_profiler/config'
|
15
|
+
require 'mini_profiler/profiling_methods'
|
16
|
+
require 'mini_profiler/context'
|
15
17
|
|
16
18
|
module Rack
|
17
19
|
|
18
20
|
class MiniProfiler
|
19
21
|
|
20
|
-
VERSION = '
|
21
|
-
@@instance = nil
|
22
|
+
VERSION = '104'.freeze
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
class << self
|
25
|
+
|
26
|
+
include Rack::MiniProfiler::ProfilingMethods
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def generate_id
|
29
|
+
rand(36**20).to_s(36)
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def reset_config
|
33
|
+
@config = Config.default
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
# So we can change the configuration if we want
|
37
|
+
def config
|
38
|
+
@config ||= Config.default
|
39
|
+
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
def share_template
|
42
|
+
return @share_template unless @share_template.nil?
|
43
|
+
@share_template = ::File.read(::File.expand_path("../html/share.html", ::File.dirname(__FILE__)))
|
44
|
+
end
|
45
|
+
|
46
|
+
def current
|
47
|
+
Thread.current[:mini_profiler_private]
|
48
|
+
end
|
49
|
+
|
50
|
+
def current=(c)
|
51
|
+
# we use TLS cause we need access to this from sql blocks and code blocks that have no access to env
|
52
|
+
Thread.current[:mini_profiler_private]= c
|
53
|
+
end
|
54
|
+
|
55
|
+
# discard existing results, don't track this request
|
56
|
+
def discard_results
|
57
|
+
self.current.discard = true if current
|
58
|
+
end
|
59
|
+
|
60
|
+
# user has the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
61
|
+
def has_profiling_cookie?(env)
|
62
|
+
env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin=stylin")
|
63
|
+
end
|
64
|
+
|
65
|
+
# remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
|
66
|
+
def remove_profiling_cookie(headers)
|
67
|
+
Rack::Utils.delete_cookie_header!(headers, '__profilin')
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_profiling_cookie(headers)
|
71
|
+
Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_current(env={}, options={})
|
75
|
+
# profiling the request
|
76
|
+
self.current = Context.new
|
77
|
+
self.current.inject_js = config.auto_inject && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
|
78
|
+
self.current.page_struct = PageTimerStruct.new(env)
|
79
|
+
self.current.current_timer = current.page_struct['Root']
|
80
|
+
end
|
81
|
+
|
82
|
+
def authorize_request
|
83
|
+
Thread.current[:mp_authorized] = true
|
84
|
+
end
|
85
|
+
|
86
|
+
def deauthorize_request
|
87
|
+
Thread.current[:mp_authorized] = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def request_authorized?
|
91
|
+
Thread.current[:mp_authorized]
|
92
|
+
end
|
43
93
|
end
|
44
94
|
|
45
95
|
#
|
46
96
|
# options:
|
47
97
|
# :auto_inject - should script be automatically injected on every html page (not xhr)
|
48
98
|
def initialize(app, config = nil)
|
49
|
-
@@instance = self
|
50
99
|
MiniProfiler.config.merge!(config)
|
51
100
|
@config = MiniProfiler.config
|
52
101
|
@app = app
|
@@ -106,31 +155,7 @@ module Rack
|
|
106
155
|
f.serving env
|
107
156
|
end
|
108
157
|
|
109
|
-
|
110
|
-
Thread.current['profiler.mini.private']
|
111
|
-
end
|
112
|
-
|
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
|
-
|
118
|
-
def self.discard_results
|
119
|
-
current[:discard] = true if current
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.has_profiling_cookie?(env)
|
123
|
-
env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin=stylin")
|
124
|
-
end
|
125
|
-
|
126
|
-
def self.remove_profiling_cookie(headers)
|
127
|
-
Rack::Utils.delete_cookie_header!(headers, '__profilin')
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.set_profiling_cookie(headers)
|
131
|
-
Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
|
132
|
-
end
|
133
|
-
|
158
|
+
|
134
159
|
def current
|
135
160
|
MiniProfiler.current
|
136
161
|
end
|
@@ -139,33 +164,26 @@ module Rack
|
|
139
164
|
MiniProfiler.current=c
|
140
165
|
end
|
141
166
|
|
167
|
+
|
142
168
|
def config
|
143
169
|
@config
|
144
170
|
end
|
145
171
|
|
146
|
-
def self.create_current(env={}, options={})
|
147
|
-
# profiling the request
|
148
|
-
self.current = {}
|
149
|
-
self.current['inject_js'] = config.auto_inject && (!env['HTTP_X_REQUESTED_WITH'].eql? 'XMLHttpRequest')
|
150
|
-
self.current['page_struct'] = PageTimerStruct.new(env)
|
151
|
-
self.current['current_timer'] = current['page_struct']['Root']
|
152
|
-
end
|
153
|
-
|
154
172
|
|
155
173
|
def call(env)
|
156
|
-
|
157
|
-
|
174
|
+
status = headers = body = nil
|
158
175
|
path = env['PATH_INFO']
|
159
|
-
# only profile if authorized
|
160
|
-
if !@config.pre_authorize_cb.call(env) ||
|
161
|
-
(@config.skip_paths && @config.skip_paths.any?{ |p| path[0,p.length] == p}) ||
|
162
|
-
env["QUERY_STRING"] =~ /pp=skip/
|
163
176
|
|
177
|
+
skip_it = (@config.pre_authorize_cb && !@config.pre_authorize_cb.call(env)) ||
|
178
|
+
(@config.skip_paths && @config.skip_paths.any?{ |p| path[0,p.length] == p}) ||
|
179
|
+
env["QUERY_STRING"] =~ /pp=skip/
|
180
|
+
|
181
|
+
has_profiling_cookie = MiniProfiler.has_profiling_cookie?(env)
|
182
|
+
|
183
|
+
if skip_it || (@config.authorization_mode == :whitelist && !has_profiling_cookie)
|
164
184
|
status,headers,body = @app.call(env)
|
165
|
-
if @config.
|
166
|
-
|
167
|
-
self.class.set_profiling_cookie(headers)
|
168
|
-
end
|
185
|
+
if !skip_it && @config.authorization_mode == :whitelist && !has_profiling_cookie && MiniProfiler.request_authorized?
|
186
|
+
MiniProfiler.set_profiling_cookie(headers)
|
169
187
|
end
|
170
188
|
return [status,headers,body]
|
171
189
|
end
|
@@ -174,30 +192,38 @@ module Rack
|
|
174
192
|
return serve_html(env) if env['PATH_INFO'].start_with? @config.base_url_path
|
175
193
|
|
176
194
|
MiniProfiler.create_current(env, @config)
|
195
|
+
MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
|
177
196
|
if env["QUERY_STRING"] =~ /pp=no-backtrace/
|
178
|
-
current
|
197
|
+
current.skip_backtrace = true
|
198
|
+
elsif env["QUERY_STRING"] =~ /pp=full-backtrace/
|
199
|
+
current.full_backtrace = true
|
179
200
|
end
|
180
|
-
|
201
|
+
|
181
202
|
done_sampling = false
|
182
203
|
quit_sampler = false
|
183
204
|
backtraces = nil
|
205
|
+
missing_stacktrace = false
|
184
206
|
if env["QUERY_STRING"] =~ /pp=sample/
|
185
207
|
backtraces = []
|
186
208
|
t = Thread.current
|
187
209
|
Thread.new {
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
i
|
197
|
-
|
198
|
-
|
210
|
+
begin
|
211
|
+
require 'stacktrace' rescue nil
|
212
|
+
if !t.respond_to? :stacktrace
|
213
|
+
missing_stacktrace = true
|
214
|
+
quit_sampler = true
|
215
|
+
return
|
216
|
+
end
|
217
|
+
i = 10000 # for sanity never grab more than 10k samples
|
218
|
+
while i > 0
|
219
|
+
break if done_sampling
|
220
|
+
i -= 1
|
221
|
+
backtraces << t.stacktrace
|
222
|
+
sleep 0.001
|
223
|
+
end
|
224
|
+
ensure
|
225
|
+
quit_sampler = true
|
199
226
|
end
|
200
|
-
quit_sampler = true
|
201
227
|
}
|
202
228
|
end
|
203
229
|
|
@@ -212,15 +238,15 @@ module Rack
|
|
212
238
|
end
|
213
239
|
end
|
214
240
|
|
215
|
-
skip_it = current
|
216
|
-
if
|
217
|
-
|
241
|
+
skip_it = current.discard
|
242
|
+
if (config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
|
243
|
+
MiniProfiler.remove_profiling_cookie(headers)
|
218
244
|
skip_it = true
|
219
245
|
end
|
220
|
-
|
246
|
+
|
221
247
|
return [status,headers,body] if skip_it
|
222
248
|
|
223
|
-
# we must do this here, otherwise current[
|
249
|
+
# we must do this here, otherwise current[:discard] is not being properly treated
|
224
250
|
if env["QUERY_STRING"] =~ /pp=env/
|
225
251
|
body.close if body.respond_to? :close
|
226
252
|
return dump_env env
|
@@ -231,11 +257,12 @@ module Rack
|
|
231
257
|
return help
|
232
258
|
end
|
233
259
|
|
234
|
-
page_struct = current
|
260
|
+
page_struct = current.page_struct
|
235
261
|
page_struct['Root'].record_time((Time.now - start) * 1000)
|
236
262
|
|
237
263
|
if backtraces
|
238
264
|
body.close if body.respond_to? :close
|
265
|
+
return help(:stacktrace) if missing_stacktrace
|
239
266
|
return analyze(backtraces, page_struct)
|
240
267
|
end
|
241
268
|
|
@@ -253,7 +280,7 @@ module Rack
|
|
253
280
|
end
|
254
281
|
|
255
282
|
# inject script
|
256
|
-
if current
|
283
|
+
if current.inject_js \
|
257
284
|
&& headers.has_key?('Content-Type') \
|
258
285
|
&& !headers['Content-Type'].match(/text\/html/).nil? then
|
259
286
|
body = MiniProfiler::BodyAddProxy.new(body, self.get_profile_script(env))
|
@@ -280,34 +307,59 @@ module Rack
|
|
280
307
|
[200, headers, [body]]
|
281
308
|
end
|
282
309
|
|
283
|
-
def help
|
310
|
+
def help(category = nil)
|
284
311
|
headers = {'Content-Type' => 'text/plain'}
|
285
312
|
body = "Append the following to your query string:
|
286
313
|
|
287
314
|
pp=help : display this screen
|
288
315
|
pp=env : display the rack environment
|
289
316
|
pp=skip : skip mini profiler for this request
|
290
|
-
pp=no-backtrace : don't collect stack traces from all the SQL
|
317
|
+
pp=no-backtrace : don't collect stack traces from all the SQL executed
|
318
|
+
pp=full-backtrace : enable full backtrace for SQL executed
|
291
319
|
pp=sample : sample stack traces and return a report isolating heavy usage (requires the stacktrace gem)
|
292
320
|
"
|
293
|
-
|
321
|
+
if (category == :stacktrace)
|
322
|
+
body = "pp=stacktrace requires the stacktrace gem - add gem 'stacktrace' to your Gemfile"
|
323
|
+
end
|
324
|
+
|
294
325
|
[200, headers, [body]]
|
295
326
|
end
|
296
327
|
|
297
328
|
def analyze(traces, page_struct)
|
298
329
|
headers = {'Content-Type' => 'text/plain'}
|
299
330
|
body = "Collected: #{traces.count} stack traces. Duration(ms): #{page_struct.duration_ms}"
|
331
|
+
|
332
|
+
seen = {}
|
333
|
+
fulldump = ""
|
300
334
|
traces.each do |trace|
|
301
|
-
|
335
|
+
fulldump << "\n\n"
|
336
|
+
distinct = {}
|
302
337
|
trace.each do |frame|
|
303
|
-
|
338
|
+
name = "#{frame.klass} #{frame.method}"
|
339
|
+
unless distinct[name]
|
340
|
+
distinct[name] = true
|
341
|
+
seen[name] ||= 0
|
342
|
+
seen[name] += 1
|
343
|
+
end
|
344
|
+
fulldump << name << "\n"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
body << "\n\nStack Trace Analysis\n"
|
349
|
+
seen.to_a.sort{|x,y| y[1] <=> x[1]}.each do |name, count|
|
350
|
+
if count > traces.count / 10
|
351
|
+
body << "#{name} x #{count}\n"
|
304
352
|
end
|
305
353
|
end
|
354
|
+
|
355
|
+
body << "\n\n\nRaw traces \n"
|
356
|
+
body << fulldump
|
357
|
+
|
306
358
|
[200, headers, [body]]
|
307
359
|
end
|
308
360
|
|
309
361
|
def ids_json(env)
|
310
|
-
ids = [current
|
362
|
+
ids = [current.page_struct["Id"]] + (@storage.get_unviewed_ids(user(env)) || [])
|
311
363
|
::JSON.generate(ids.uniq)
|
312
364
|
end
|
313
365
|
|
@@ -326,7 +378,7 @@ module Rack
|
|
326
378
|
showChildren = false
|
327
379
|
maxTracesToShow = 10
|
328
380
|
showControls = false
|
329
|
-
currentId = current
|
381
|
+
currentId = current.page_struct["Id"]
|
330
382
|
authorized = true
|
331
383
|
useExistingjQuery = false
|
332
384
|
# TODO : cache this snippet
|
@@ -338,52 +390,13 @@ module Rack
|
|
338
390
|
end
|
339
391
|
# replace the '{{' and '}}''
|
340
392
|
script.gsub!(/\{\{/, '{').gsub!(/\}\}/, '}')
|
341
|
-
current
|
393
|
+
current.inject_js = false
|
342
394
|
script
|
343
395
|
end
|
344
396
|
|
345
397
|
# cancels automatic injection of profile script for the current page
|
346
398
|
def cancel_auto_inject(env)
|
347
|
-
current
|
348
|
-
end
|
349
|
-
|
350
|
-
# perform a profiling step on given block
|
351
|
-
def self.step(name)
|
352
|
-
if current
|
353
|
-
old_timer = current['current_timer']
|
354
|
-
new_step = RequestTimerStruct.new(name, current['page_struct'])
|
355
|
-
current['current_timer'] = new_step
|
356
|
-
new_step['Name'] = name
|
357
|
-
start = Time.now
|
358
|
-
result = yield if block_given?
|
359
|
-
new_step.record_time((Time.now - start)*1000)
|
360
|
-
old_timer.add_child(new_step)
|
361
|
-
current['current_timer'] = old_timer
|
362
|
-
result
|
363
|
-
else
|
364
|
-
yield if block_given?
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
def self.profile_method(klass, method, &blk)
|
369
|
-
default_name = klass.to_s + " " + method.to_s
|
370
|
-
with_profiling = (method.to_s + "_with_mini_profiler").intern
|
371
|
-
without_profiling = (method.to_s + "_without_mini_profiler").intern
|
372
|
-
|
373
|
-
klass.send :alias_method, without_profiling, method
|
374
|
-
klass.send :define_method, with_profiling do |*args, &orig|
|
375
|
-
name = default_name
|
376
|
-
name = blk.bind(self).call(*args) if blk
|
377
|
-
::Rack::MiniProfiler.step name do
|
378
|
-
self.send without_profiling, *args, &orig
|
379
|
-
end
|
380
|
-
end
|
381
|
-
klass.send :alias_method, method, with_profiling
|
382
|
-
end
|
383
|
-
|
384
|
-
def record_sql(query, elapsed_ms)
|
385
|
-
c = current
|
386
|
-
c['current_timer'].add_sql(query, elapsed_ms, c['page_struct'], c['skip-backtrace']) if (c && c['current_timer'])
|
399
|
+
current.inject_js = false
|
387
400
|
end
|
388
401
|
|
389
402
|
end
|