rack-mini-profiler 0.1.4 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +14 -0
- data/README.md +25 -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 +6 -4
- data/lib/mini_profiler/config.rb +2 -1
- data/lib/mini_profiler/page_timer_struct.rb +1 -1
- data/lib/mini_profiler/profiler.rb +45 -14
- 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 +4 -2
- data/lib/patches/sql_patches.rb +37 -30
- data/lib/rack-mini-profiler.rb +3 -3
- data/rack-mini-profiler.gemspec +3 -4
- metadata +4 -6
- data/lib/html/MiniProfilerHandler.cs +0 -419
- data/lib/mini_profiler/body_add_proxy.rb +0 -45
data/CHANGELOG
CHANGED
|
@@ -24,3 +24,17 @@
|
|
|
24
24
|
* Added some more client probing built in to rails
|
|
25
25
|
* More tests
|
|
26
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
|
+
|
|
33
|
+
30-July-2012 - Sam
|
|
34
|
+
|
|
35
|
+
* Made compliant with ancient versions of Rack (including Rack used by Rails2)
|
|
36
|
+
* Fixed broken share link
|
|
37
|
+
* Fixed crashes on startup (in MemoryStore and FileStore)
|
|
38
|
+
* Version 0.1.8
|
|
39
|
+
* Unicode fix
|
|
40
|
+
* Version 0.1.9
|
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
|
```
|
|
@@ -67,11 +85,18 @@ Rack::MiniProfiler.config.position = 'right'
|
|
|
67
85
|
|
|
68
86
|
In a Rails app, this can be done conveniently in an initializer such as config/initializers/mini_profiler.rb.
|
|
69
87
|
|
|
88
|
+
## Rails 2.X support
|
|
89
|
+
|
|
90
|
+
MiniProfiler uses [railtie](https://github.com/SamSaffron/MiniProfiler/blob/master/Ruby/lib/mini_profiler_rails/railtie.rb) to bootstrap itself. This will not be called in a Rails 2 app. You are going to need to hook it up manually. (TODO: document this - pull request please)
|
|
91
|
+
|
|
70
92
|
## Available Options
|
|
71
93
|
|
|
72
94
|
* 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.
|
|
73
95
|
* position - Can either be 'right' or 'left'. Default is 'left'.
|
|
74
96
|
* 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.
|
|
97
|
+
* use_existing_jquery - Use the version of jQuery on the page as opposed to the self contained one
|
|
98
|
+
* auto_inject (default true) - when false the miniprofiler script is not injected in the page
|
|
99
|
+
* backtrace_filter - a regex you can use to filter out unwanted lines from the backtraces
|
|
75
100
|
|
|
76
101
|
## Special query strings
|
|
77
102
|
|
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>
|
|
@@ -23,7 +23,7 @@ module Rack
|
|
|
23
23
|
super
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def init_from_form_data(env, page_struct)
|
|
26
|
+
def self.init_from_form_data(env, page_struct)
|
|
27
27
|
timings = []
|
|
28
28
|
clientTimes, clientPerf, baseTime = nil
|
|
29
29
|
form = env['rack.request.form_hash']
|
|
@@ -36,7 +36,7 @@ module Rack
|
|
|
36
36
|
|
|
37
37
|
probes = form['clientProbes']
|
|
38
38
|
translated = {}
|
|
39
|
-
if probes
|
|
39
|
+
if probes && probes != "null"
|
|
40
40
|
probes.each do |id, val|
|
|
41
41
|
name = val["n"]
|
|
42
42
|
translated[name] ||= {}
|
|
@@ -67,8 +67,10 @@ module Rack
|
|
|
67
67
|
timings.push("Name" => k, "Start" => clientTimes[k].to_i - baseTime, "Duration" => -1)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
rval = self.new
|
|
71
|
+
rval['RedirectCount'] = env['rack.request.form_hash']['clientPerformance']['navigation']['redirectCount']
|
|
72
|
+
rval['Timings'] = timings
|
|
73
|
+
rval
|
|
72
74
|
end
|
|
73
75
|
end
|
|
74
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
|
|
@@ -6,7 +6,6 @@ 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'
|
|
@@ -19,7 +18,7 @@ module Rack
|
|
|
19
18
|
|
|
20
19
|
class MiniProfiler
|
|
21
20
|
|
|
22
|
-
VERSION = '
|
|
21
|
+
VERSION = '104'.freeze
|
|
23
22
|
|
|
24
23
|
class << self
|
|
25
24
|
|
|
@@ -101,8 +100,9 @@ module Rack
|
|
|
101
100
|
@app = app
|
|
102
101
|
@config.base_url_path << "/" unless @config.base_url_path.end_with? "/"
|
|
103
102
|
unless @config.storage_instance
|
|
104
|
-
@
|
|
103
|
+
@config.storage_instance = @config.storage.new(@config.storage_options)
|
|
105
104
|
end
|
|
105
|
+
@storage = @config.storage_instance
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def user(env)
|
|
@@ -118,7 +118,7 @@ module Rack
|
|
|
118
118
|
return [404, {}, ["Request not found: #{request['id']} - user #{user(env)}"]]
|
|
119
119
|
end
|
|
120
120
|
unless page_struct['HasUserViewed']
|
|
121
|
-
|
|
121
|
+
page_struct['ClientTimings'] = ClientTimerStruct.init_from_form_data(env, page_struct)
|
|
122
122
|
page_struct['HasUserViewed'] = true
|
|
123
123
|
@storage.save(page_struct)
|
|
124
124
|
@storage.set_viewed(user(env), id)
|
|
@@ -151,8 +151,17 @@ module Rack
|
|
|
151
151
|
return [404, {}, ["Not found"]] unless ::File.exists? full_path
|
|
152
152
|
f = Rack::File.new nil
|
|
153
153
|
f.path = full_path
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
|
|
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
|
+
|
|
156
165
|
end
|
|
157
166
|
|
|
158
167
|
|
|
@@ -245,7 +254,7 @@ module Rack
|
|
|
245
254
|
end
|
|
246
255
|
|
|
247
256
|
return [status,headers,body] if skip_it
|
|
248
|
-
|
|
257
|
+
|
|
249
258
|
# we must do this here, otherwise current[:discard] is not being properly treated
|
|
250
259
|
if env["QUERY_STRING"] =~ /pp=env/
|
|
251
260
|
body.close if body.respond_to? :close
|
|
@@ -274,6 +283,12 @@ module Rack
|
|
|
274
283
|
# inject headers, script
|
|
275
284
|
if status == 200
|
|
276
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
|
+
|
|
277
292
|
# inject header
|
|
278
293
|
if headers.is_a? Hash
|
|
279
294
|
headers['X-MiniProfiler-Ids'] = ids_json(env)
|
|
@@ -283,21 +298,37 @@ module Rack
|
|
|
283
298
|
if current.inject_js \
|
|
284
299
|
&& headers.has_key?('Content-Type') \
|
|
285
300
|
&& !headers['Content-Type'].match(/text\/html/).nil? then
|
|
286
|
-
|
|
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
|
|
287
311
|
end
|
|
288
312
|
end
|
|
289
313
|
|
|
290
|
-
# mini profiler is meddling with stuff, we can not cache cause we will get incorrect data
|
|
291
|
-
# Rack::ETag has already inserted some nonesense in the chain
|
|
292
|
-
headers.delete('ETag')
|
|
293
|
-
headers.delete('Date')
|
|
294
|
-
headers['Cache-Control'] = 'must-revalidate, private, max-age=0'
|
|
295
314
|
[status, headers, body]
|
|
296
315
|
ensure
|
|
297
316
|
# Make sure this always happens
|
|
298
317
|
current = nil
|
|
299
318
|
end
|
|
300
319
|
|
|
320
|
+
def inject(fragment, script)
|
|
321
|
+
fragment.sub(/<\/body>/i) do
|
|
322
|
+
# if for whatever crazy reason we dont get a utf string,
|
|
323
|
+
# just force the encoding, no utf in the mp scripts anyway
|
|
324
|
+
if script.respond_to?(:encoding) && script.respond_to?(:force_encoding)
|
|
325
|
+
(script + "</body>").force_encoding(fragment.encoding)
|
|
326
|
+
else
|
|
327
|
+
script + "</body>"
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
301
332
|
def dump_env(env)
|
|
302
333
|
headers = {'Content-Type' => 'text/plain'}
|
|
303
334
|
body = ""
|
|
@@ -380,7 +411,7 @@ module Rack
|
|
|
380
411
|
showControls = false
|
|
381
412
|
currentId = current.page_struct["Id"]
|
|
382
413
|
authorized = true
|
|
383
|
-
|
|
414
|
+
useExistingjQuery = @config.use_existing_jquery
|
|
384
415
|
# TODO : cache this snippet
|
|
385
416
|
script = IO.read(::File.expand_path('../html/profile_handler.js', ::File.dirname(__FILE__)))
|
|
386
417
|
# replace the variables
|
|
@@ -39,9 +39,14 @@ module Rack
|
|
|
39
39
|
|
|
40
40
|
me = self
|
|
41
41
|
Thread.new do
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
begin
|
|
43
|
+
while true do
|
|
44
|
+
# TODO: a sane retry count before bailing
|
|
45
|
+
me.cleanup_cache
|
|
46
|
+
sleep(3600)
|
|
47
|
+
end
|
|
48
|
+
rescue
|
|
49
|
+
# don't crash the thread, we can clean up next time
|
|
45
50
|
end
|
|
46
51
|
end
|
|
47
52
|
end
|
|
@@ -83,10 +88,6 @@ module Rack
|
|
|
83
88
|
}
|
|
84
89
|
end
|
|
85
90
|
|
|
86
|
-
|
|
87
|
-
private
|
|
88
|
-
|
|
89
|
-
|
|
90
91
|
def cleanup_cache
|
|
91
92
|
files = Dir.entries(@path)
|
|
92
93
|
@timer_struct_lock.synchronize {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
1
3
|
module MiniProfilerRails
|
|
2
4
|
|
|
3
5
|
class Railtie < ::Rails::Railtie
|
|
@@ -22,7 +24,7 @@ module MiniProfilerRails
|
|
|
22
24
|
|
|
23
25
|
# The file store is just so much less flaky
|
|
24
26
|
tmp = Rails.root.to_s + "/tmp/miniprofiler"
|
|
25
|
-
|
|
27
|
+
FileUtils.mkdir_p(tmp) unless File.exists?(tmp)
|
|
26
28
|
|
|
27
29
|
c.storage_options = {:path => tmp}
|
|
28
30
|
c.storage = Rack::MiniProfiler::FileStore
|
|
@@ -76,7 +78,7 @@ module MiniProfilerRails
|
|
|
76
78
|
# end
|
|
77
79
|
# end
|
|
78
80
|
|
|
79
|
-
end
|
|
81
|
+
# end
|
|
80
82
|
|
|
81
83
|
end
|
|
82
84
|
end
|
data/lib/patches/sql_patches.rb
CHANGED
|
@@ -13,6 +13,12 @@ class SqlPatches
|
|
|
13
13
|
rescue NameError
|
|
14
14
|
false
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
def self.module_exists?(name)
|
|
18
|
+
eval(name + ".class").to_s.eql?('Module')
|
|
19
|
+
rescue NameError
|
|
20
|
+
false
|
|
21
|
+
end
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
# The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
|
|
@@ -134,45 +140,46 @@ end
|
|
|
134
140
|
|
|
135
141
|
## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
|
|
136
142
|
## fallback for alls sorts of weird dbs
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
instrumented_class
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
if SqlPatches.module_exists?('ActiveRecord')
|
|
144
|
+
module Rack
|
|
145
|
+
class MiniProfiler
|
|
146
|
+
module ActiveRecordInstrumentation
|
|
147
|
+
def self.included(instrumented_class)
|
|
148
|
+
instrumented_class.class_eval do
|
|
149
|
+
unless instrumented_class.method_defined?(:log_without_miniprofiler)
|
|
150
|
+
alias_method :log_without_miniprofiler, :log
|
|
151
|
+
alias_method :log, :log_with_miniprofiler
|
|
152
|
+
protected :log
|
|
153
|
+
end
|
|
146
154
|
end
|
|
147
155
|
end
|
|
148
|
-
end
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
def log_with_miniprofiler(*args, &block)
|
|
158
|
+
current = ::Rack::MiniProfiler.current
|
|
159
|
+
return log_without_miniprofiler(*args, &block) unless current
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
sql, name, binds = args
|
|
162
|
+
t0 = Time.now
|
|
163
|
+
rval = log_without_miniprofiler(*args, &block)
|
|
164
|
+
|
|
165
|
+
# Don't log schema queries if the option is set
|
|
166
|
+
return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
|
|
160
167
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
|
|
169
|
+
Rack::MiniProfiler.record_sql(sql, elapsed_time)
|
|
170
|
+
rval
|
|
171
|
+
end
|
|
164
172
|
end
|
|
165
173
|
end
|
|
166
|
-
end
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
def self.insert_instrumentation
|
|
176
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
|
|
177
|
+
include ::Rack::MiniProfiler::ActiveRecordInstrumentation
|
|
178
|
+
end
|
|
171
179
|
end
|
|
172
|
-
end
|
|
173
180
|
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
if defined?(::Rails) && !SqlPatches.patched?
|
|
182
|
+
insert_instrumentation
|
|
183
|
+
end
|
|
176
184
|
end
|
|
177
185
|
end
|
|
178
|
-
|
data/lib/rack-mini-profiler.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require 'mini_profiler/profiler'
|
|
2
|
+
require 'patches/sql_patches'
|
|
3
3
|
|
|
4
4
|
if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3
|
|
5
|
-
require
|
|
5
|
+
require 'mini_profiler_rails/railtie'
|
|
6
6
|
end
|
data/rack-mini-profiler.gemspec
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "rack-mini-profiler"
|
|
3
|
-
s.version = "0.1.
|
|
3
|
+
s.version = "0.1.9"
|
|
4
4
|
s.summary = "Profiles loading speed for rack applications."
|
|
5
5
|
s.authors = ["Aleks Totic","Sam Saffron", "Robin Ward"]
|
|
6
|
-
s.date = "2012-04-02"
|
|
7
6
|
s.description = "Page loading speed displayed on every page. Optimize while you develop, performance is a feature."
|
|
8
7
|
s.email = "sam.saffron@gmail.com"
|
|
9
8
|
s.homepage = "http://miniprofiler.com"
|
|
@@ -14,9 +13,9 @@ Gem::Specification.new do |s|
|
|
|
14
13
|
"README.md",
|
|
15
14
|
"CHANGELOG"
|
|
16
15
|
]
|
|
17
|
-
s.add_runtime_dependency 'rack', '>= 1.1.3'
|
|
16
|
+
s.add_runtime_dependency 'rack', '>= 1.1.3'
|
|
18
17
|
if RUBY_VERSION < "1.9"
|
|
19
|
-
s.add_runtime_dependency 'json', '>= 1.6'
|
|
18
|
+
s.add_runtime_dependency 'json', '>= 1.6'
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
s.add_development_dependency 'rake'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack-mini-profiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date: 2012-
|
|
14
|
+
date: 2012-07-30 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: rack
|
|
@@ -93,7 +93,6 @@ files:
|
|
|
93
93
|
- lib/mini_profiler/page_timer_struct.rb
|
|
94
94
|
- lib/mini_profiler/context.rb
|
|
95
95
|
- lib/mini_profiler/config.rb
|
|
96
|
-
- lib/mini_profiler/body_add_proxy.rb
|
|
97
96
|
- lib/mini_profiler/profiling_methods.rb
|
|
98
97
|
- lib/mini_profiler/client_timer_struct.rb
|
|
99
98
|
- lib/mini_profiler/profiler.rb
|
|
@@ -107,7 +106,6 @@ files:
|
|
|
107
106
|
- lib/html/share.html
|
|
108
107
|
- lib/html/includes.less
|
|
109
108
|
- lib/html/list.css
|
|
110
|
-
- lib/html/MiniProfilerHandler.cs
|
|
111
109
|
- lib/html/includes.js
|
|
112
110
|
- lib/html/jquery.tmpl.js
|
|
113
111
|
- lib/html/list.tmpl
|
|
@@ -132,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
132
130
|
version: '0'
|
|
133
131
|
segments:
|
|
134
132
|
- 0
|
|
135
|
-
hash:
|
|
133
|
+
hash: 663723709
|
|
136
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
135
|
none: false
|
|
138
136
|
requirements:
|
|
@@ -141,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
139
|
version: '0'
|
|
142
140
|
segments:
|
|
143
141
|
- 0
|
|
144
|
-
hash:
|
|
142
|
+
hash: 663723709
|
|
145
143
|
requirements: []
|
|
146
144
|
rubyforge_project:
|
|
147
145
|
rubygems_version: 1.8.24
|
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
using System.Collections.Generic;
|
|
3
|
-
using System.IO;
|
|
4
|
-
using System.Web;
|
|
5
|
-
using System.Web.Routing;
|
|
6
|
-
using System.Linq;
|
|
7
|
-
|
|
8
|
-
using StackExchange.Profiling.Helpers;
|
|
9
|
-
using System.Text;
|
|
10
|
-
using System.Collections.Concurrent;
|
|
11
|
-
|
|
12
|
-
namespace StackExchange.Profiling.UI
|
|
13
|
-
{
|
|
14
|
-
/// <summary>
|
|
15
|
-
/// Understands how to route and respond to MiniProfiler UI urls.
|
|
16
|
-
/// </summary>
|
|
17
|
-
public class MiniProfilerHandler : IRouteHandler, IHttpHandler
|
|
18
|
-
{
|
|
19
|
-
internal static HtmlString RenderIncludes(MiniProfiler profiler, RenderPosition? position = null, bool? showTrivial = null, bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool? showControls = null, bool? useExistingjQuery = null)
|
|
20
|
-
{
|
|
21
|
-
string format = GetResource("include.partial.html");
|
|
22
|
-
|
|
23
|
-
var result = "";
|
|
24
|
-
|
|
25
|
-
if (profiler != null)
|
|
26
|
-
{
|
|
27
|
-
// HACK: unviewed ids are added to this list during Storage.Save, but we know we haven't see the current one yet,
|
|
28
|
-
// so go ahead and add it to the end - it's usually the only id, but if there was a redirect somewhere, it'll be there, too
|
|
29
|
-
MiniProfiler.Settings.EnsureStorageStrategy();
|
|
30
|
-
|
|
31
|
-
var authorized =
|
|
32
|
-
MiniProfiler.Settings.Results_Authorize == null ||
|
|
33
|
-
MiniProfiler.Settings.Results_Authorize(HttpContext.Current.Request);
|
|
34
|
-
|
|
35
|
-
List<Guid> ids;
|
|
36
|
-
if (authorized)
|
|
37
|
-
{
|
|
38
|
-
ids = MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User);
|
|
39
|
-
ids.Add(profiler.Id);
|
|
40
|
-
}
|
|
41
|
-
else
|
|
42
|
-
{
|
|
43
|
-
ids = new List<Guid> { profiler.Id };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
result = format.Format(new
|
|
47
|
-
{
|
|
48
|
-
path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(),
|
|
49
|
-
version = MiniProfiler.Settings.Version,
|
|
50
|
-
ids = ids.ToJson(),
|
|
51
|
-
position = (position ?? MiniProfiler.Settings.PopupRenderPosition).ToString().ToLower(),
|
|
52
|
-
showTrivial = showTrivial ?? MiniProfiler.Settings.PopupShowTrivial ? "true" : "false",
|
|
53
|
-
showChildren = showTimeWithChildren ?? MiniProfiler.Settings.PopupShowTimeWithChildren ? "true" : "false",
|
|
54
|
-
maxTracesToShow = maxTracesToShow ?? MiniProfiler.Settings.PopupMaxTracesToShow,
|
|
55
|
-
showControls = showControls ?? MiniProfiler.Settings.ShowControls ? "true" : "false",
|
|
56
|
-
currentId = profiler.Id,
|
|
57
|
-
authorized = authorized ? "true" : "false",
|
|
58
|
-
useExistingjQuery = useExistingjQuery ?? MiniProfiler.Settings.UseExistingjQuery ? "true" : "false"
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return new HtmlString(result);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/// <summary>
|
|
67
|
-
/// Usually called internally, sometimes you may clear the routes during the apps lifecycle, if you do that call this to bring back mp
|
|
68
|
-
/// </summary>
|
|
69
|
-
public static void RegisterRoutes()
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
var routes = RouteTable.Routes;
|
|
73
|
-
var handler = new MiniProfilerHandler();
|
|
74
|
-
var prefix = MiniProfiler.Settings.RouteBasePath.Replace("~/", "").EnsureTrailingSlash();
|
|
75
|
-
|
|
76
|
-
using (routes.GetWriteLock())
|
|
77
|
-
{
|
|
78
|
-
var route = new Route(prefix + "{filename}", handler)
|
|
79
|
-
{
|
|
80
|
-
// we have to specify these, so no MVC route helpers will match, e.g. @Html.ActionLink("Home", "Index", "Home")
|
|
81
|
-
Defaults = new RouteValueDictionary( new { controller = "MiniProfilerHandler", action = "ProcessRequest" }),
|
|
82
|
-
Constraints = new RouteValueDictionary( new { controller = "MiniProfilerHandler", action = "ProcessRequest" })
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// put our routes at the beginning, like a boss
|
|
86
|
-
routes.Insert(0, route);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/// <summary>
|
|
91
|
-
/// Returns this <see cref="MiniProfilerHandler"/> to handle <paramref name="requestContext"/>.
|
|
92
|
-
/// </summary>
|
|
93
|
-
public IHttpHandler GetHttpHandler(RequestContext requestContext)
|
|
94
|
-
{
|
|
95
|
-
return this; // elegant? I THINK SO.
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/// <summary>
|
|
99
|
-
/// Try to keep everything static so we can easily be reused.
|
|
100
|
-
/// </summary>
|
|
101
|
-
public bool IsReusable
|
|
102
|
-
{
|
|
103
|
-
get { return true; }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/// <summary>
|
|
107
|
-
/// Returns either includes' css/javascript or results' html.
|
|
108
|
-
/// </summary>
|
|
109
|
-
public void ProcessRequest(HttpContext context)
|
|
110
|
-
{
|
|
111
|
-
string output;
|
|
112
|
-
string path = context.Request.AppRelativeCurrentExecutionFilePath;
|
|
113
|
-
|
|
114
|
-
switch (Path.GetFileNameWithoutExtension(path).ToLowerInvariant())
|
|
115
|
-
{
|
|
116
|
-
case "jquery.1.7.1":
|
|
117
|
-
case "jquery.tmpl":
|
|
118
|
-
case "includes":
|
|
119
|
-
case "list":
|
|
120
|
-
output = Includes(context, path);
|
|
121
|
-
break;
|
|
122
|
-
|
|
123
|
-
case "results-index":
|
|
124
|
-
output = Index(context);
|
|
125
|
-
break;
|
|
126
|
-
|
|
127
|
-
case "results-list":
|
|
128
|
-
output = ResultList(context);
|
|
129
|
-
break;
|
|
130
|
-
|
|
131
|
-
case "results":
|
|
132
|
-
output = Results(context);
|
|
133
|
-
break;
|
|
134
|
-
|
|
135
|
-
default:
|
|
136
|
-
output = NotFound(context);
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
context.Response.Write(output);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private static string ResultList(HttpContext context)
|
|
144
|
-
{
|
|
145
|
-
string message;
|
|
146
|
-
if (!AuthorizeRequest(context, isList: true, message: out message))
|
|
147
|
-
{
|
|
148
|
-
return message;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
var lastId = context.Request["last-id"];
|
|
152
|
-
Guid lastGuid = Guid.Empty;
|
|
153
|
-
|
|
154
|
-
if (!lastId.IsNullOrWhiteSpace()) {
|
|
155
|
-
Guid.TryParse(lastId, out lastGuid);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
var guids = MiniProfiler.Settings.Storage.List(100);
|
|
159
|
-
|
|
160
|
-
if (lastGuid != Guid.Empty)
|
|
161
|
-
{
|
|
162
|
-
guids = guids.TakeWhile(g => g != lastGuid);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
guids = guids.Reverse();
|
|
166
|
-
|
|
167
|
-
return guids.Select(g =>
|
|
168
|
-
{
|
|
169
|
-
var profiler = MiniProfiler.Settings.Storage.Load(g);
|
|
170
|
-
return new
|
|
171
|
-
{
|
|
172
|
-
profiler.Id,
|
|
173
|
-
profiler.Name,
|
|
174
|
-
profiler.DurationMilliseconds,
|
|
175
|
-
profiler.DurationMillisecondsInSql,
|
|
176
|
-
profiler.ClientTimings,
|
|
177
|
-
profiler.Started,
|
|
178
|
-
profiler.ExecutedNonQueries,
|
|
179
|
-
profiler.ExecutedReaders,
|
|
180
|
-
profiler.ExecutedScalars,
|
|
181
|
-
profiler.HasAllTrivialTimings,
|
|
182
|
-
profiler.HasDuplicateSqlTimings,
|
|
183
|
-
profiler.HasSqlTimings,
|
|
184
|
-
profiler.HasTrivialTimings,
|
|
185
|
-
profiler.HasUserViewed,
|
|
186
|
-
profiler.MachineName,
|
|
187
|
-
profiler.User
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
).ToJson();
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
private static string Index(HttpContext context)
|
|
195
|
-
{
|
|
196
|
-
string message;
|
|
197
|
-
if (!AuthorizeRequest(context, isList: true, message: out message))
|
|
198
|
-
{
|
|
199
|
-
return message;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
context.Response.ContentType = "text/html";
|
|
203
|
-
|
|
204
|
-
var path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash();
|
|
205
|
-
|
|
206
|
-
return new StringBuilder()
|
|
207
|
-
.AppendLine("<html><head>")
|
|
208
|
-
.AppendFormat("<title>List of profiling sessions</title>")
|
|
209
|
-
.AppendLine()
|
|
210
|
-
.AppendLine("<script type='text/javascript' src='" + path + "jquery.1.7.1.js?v=" + MiniProfiler.Settings.Version + "'></script>")
|
|
211
|
-
.AppendLine("<script type='text/javascript' src='" + path + "jquery.tmpl.js?v=" + MiniProfiler.Settings.Version + "'></script>")
|
|
212
|
-
.AppendLine("<script type='text/javascript' src='" + path + "includes.js?v=" + MiniProfiler.Settings.Version + "'></script>")
|
|
213
|
-
.AppendLine("<script type='text/javascript' src='" + path + "list.js?v=" + MiniProfiler.Settings.Version + "'></script>")
|
|
214
|
-
.AppendLine("<link href='" + path +"list.css?v=" + MiniProfiler.Settings.Version + "' rel='stylesheet' type='text/css'>")
|
|
215
|
-
.AppendLine("<script type='text/javascript'>MiniProfiler.list.init({path: '" + path + "', version: '" + MiniProfiler.Settings.Version + "'})</script>")
|
|
216
|
-
.AppendLine("</head><body></body></html>")
|
|
217
|
-
.ToString();
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/// <summary>
|
|
221
|
-
/// Handles rendering static content files.
|
|
222
|
-
/// </summary>
|
|
223
|
-
private static string Includes(HttpContext context, string path)
|
|
224
|
-
{
|
|
225
|
-
var response = context.Response;
|
|
226
|
-
|
|
227
|
-
switch (Path.GetExtension(path))
|
|
228
|
-
{
|
|
229
|
-
case ".js":
|
|
230
|
-
response.ContentType = "application/javascript";
|
|
231
|
-
break;
|
|
232
|
-
case ".css":
|
|
233
|
-
response.ContentType = "text/css";
|
|
234
|
-
break;
|
|
235
|
-
case ".tmpl":
|
|
236
|
-
response.ContentType = "text/x-jquery-tmpl";
|
|
237
|
-
break;
|
|
238
|
-
default:
|
|
239
|
-
return NotFound(context);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
#if !DEBUG
|
|
243
|
-
var cache = response.Cache;
|
|
244
|
-
cache.SetCacheability(System.Web.HttpCacheability.Public);
|
|
245
|
-
cache.SetExpires(DateTime.Now.AddDays(7));
|
|
246
|
-
cache.SetValidUntilExpires(true);
|
|
247
|
-
#endif
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
var embeddedFile = Path.GetFileName(path);
|
|
251
|
-
return GetResource(embeddedFile);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/// <summary>
|
|
255
|
-
/// Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query.
|
|
256
|
-
/// </summary>
|
|
257
|
-
private static string Results(HttpContext context)
|
|
258
|
-
{
|
|
259
|
-
// when we're rendering as a button/popup in the corner, we'll pass ?popup=1
|
|
260
|
-
// if it's absent, we're rendering results as a full page for sharing
|
|
261
|
-
var isPopup = !string.IsNullOrWhiteSpace(context.Request["popup"]);
|
|
262
|
-
|
|
263
|
-
// this guid is the MiniProfiler.Id property
|
|
264
|
-
Guid id;
|
|
265
|
-
if (!Guid.TryParse(context.Request["id"], out id))
|
|
266
|
-
return isPopup ? NotFound(context) : NotFound(context, "text/plain", "No Guid id specified on the query string");
|
|
267
|
-
|
|
268
|
-
MiniProfiler.Settings.EnsureStorageStrategy();
|
|
269
|
-
var profiler = MiniProfiler.Settings.Storage.Load(id);
|
|
270
|
-
|
|
271
|
-
var provider = WebRequestProfilerProvider.Settings.UserProvider;
|
|
272
|
-
string user = null;
|
|
273
|
-
if (provider != null)
|
|
274
|
-
{
|
|
275
|
-
user = provider.GetUser(context.Request);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
MiniProfiler.Settings.Storage.SetViewed(user, id);
|
|
279
|
-
|
|
280
|
-
if (profiler == null)
|
|
281
|
-
{
|
|
282
|
-
return isPopup ? NotFound(context) : NotFound(context, "text/plain", "No MiniProfiler results found with Id=" + id.ToString());
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
bool needsSave = false;
|
|
286
|
-
if (profiler.ClientTimings == null)
|
|
287
|
-
{
|
|
288
|
-
profiler.ClientTimings = ClientTimings.FromRequest(context.Request);
|
|
289
|
-
if (profiler.ClientTimings != null)
|
|
290
|
-
{
|
|
291
|
-
needsSave = true;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (profiler.HasUserViewed == false)
|
|
296
|
-
{
|
|
297
|
-
profiler.HasUserViewed = true;
|
|
298
|
-
needsSave = true;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (needsSave) MiniProfiler.Settings.Storage.Save(profiler);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
var authorize = MiniProfiler.Settings.Results_Authorize;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (authorize != null && !authorize(context.Request))
|
|
308
|
-
{
|
|
309
|
-
context.Response.ContentType = "application/json";
|
|
310
|
-
return "hidden".ToJson();
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return isPopup ? ResultsJson(context, profiler) : ResultsFullPage(context, profiler);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
private static bool AuthorizeRequest(HttpContext context, bool isList, out string message)
|
|
317
|
-
{
|
|
318
|
-
message = null;
|
|
319
|
-
var authorize = MiniProfiler.Settings.Results_Authorize;
|
|
320
|
-
var authorizeList = MiniProfiler.Settings.Results_List_Authorize;
|
|
321
|
-
|
|
322
|
-
if (authorize != null && !authorize(context.Request) || (isList && (authorizeList == null || !authorizeList(context.Request))))
|
|
323
|
-
{
|
|
324
|
-
context.Response.StatusCode = 401;
|
|
325
|
-
context.Response.ContentType = "text/plain";
|
|
326
|
-
message = "unauthorized";
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
private static string ResultsJson(HttpContext context, MiniProfiler profiler)
|
|
333
|
-
{
|
|
334
|
-
context.Response.ContentType = "application/json";
|
|
335
|
-
return MiniProfiler.ToJson(profiler);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
private static string ResultsFullPage(HttpContext context, MiniProfiler profiler)
|
|
339
|
-
{
|
|
340
|
-
context.Response.ContentType = "text/html";
|
|
341
|
-
|
|
342
|
-
var template = GetResource("share.html");
|
|
343
|
-
return template.Format(new
|
|
344
|
-
{
|
|
345
|
-
name = profiler.Name,
|
|
346
|
-
duration = profiler.DurationMilliseconds.ToString(),
|
|
347
|
-
path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(),
|
|
348
|
-
json = MiniProfiler.ToJson(profiler),
|
|
349
|
-
includes = RenderIncludes(profiler),
|
|
350
|
-
version = MiniProfiler.Settings.Version
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
private static bool bypassLocalLoad = false;
|
|
355
|
-
private static string GetResource(string filename)
|
|
356
|
-
{
|
|
357
|
-
filename = filename.ToLower();
|
|
358
|
-
string result;
|
|
359
|
-
|
|
360
|
-
#if DEBUG
|
|
361
|
-
// attempt to simply load from file system, this lets up modify js without needing to recompile A MILLION TIMES
|
|
362
|
-
if (!bypassLocalLoad)
|
|
363
|
-
{
|
|
364
|
-
|
|
365
|
-
var trace = new System.Diagnostics.StackTrace(true);
|
|
366
|
-
var path = System.IO.Path.GetDirectoryName(trace.GetFrames()[0].GetFileName()) + "\\..\\UI\\" + filename;
|
|
367
|
-
try
|
|
368
|
-
{
|
|
369
|
-
return File.ReadAllText(path);
|
|
370
|
-
}
|
|
371
|
-
catch
|
|
372
|
-
{
|
|
373
|
-
bypassLocalLoad = true;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
#endif
|
|
378
|
-
|
|
379
|
-
if (!_ResourceCache.TryGetValue(filename, out result))
|
|
380
|
-
{
|
|
381
|
-
string customTemplatesPath = HttpContext.Current.Server.MapPath(MiniProfiler.Settings.CustomUITemplates);
|
|
382
|
-
string customTemplateFile = System.IO.Path.Combine(customTemplatesPath, filename);
|
|
383
|
-
|
|
384
|
-
if (System.IO.File.Exists(customTemplateFile))
|
|
385
|
-
{
|
|
386
|
-
result = File.ReadAllText(customTemplateFile);
|
|
387
|
-
}
|
|
388
|
-
else
|
|
389
|
-
{
|
|
390
|
-
using (var stream = typeof(MiniProfilerHandler).Assembly.GetManifestResourceStream("StackExchange.Profiling.UI." + filename))
|
|
391
|
-
using (var reader = new StreamReader(stream))
|
|
392
|
-
{
|
|
393
|
-
result = reader.ReadToEnd();
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
_ResourceCache[filename] = result;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return result;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/// <summary>
|
|
403
|
-
/// Embedded resource contents keyed by filename.
|
|
404
|
-
/// </summary>
|
|
405
|
-
private static readonly ConcurrentDictionary<string, string> _ResourceCache = new ConcurrentDictionary<string, string>();
|
|
406
|
-
|
|
407
|
-
/// <summary>
|
|
408
|
-
/// Helper method that sets a proper 404 response code.
|
|
409
|
-
/// </summary>
|
|
410
|
-
private static string NotFound(HttpContext context, string contentType = "text/plain", string message = null)
|
|
411
|
-
{
|
|
412
|
-
context.Response.StatusCode = 404;
|
|
413
|
-
context.Response.ContentType = contentType;
|
|
414
|
-
|
|
415
|
-
return message;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
module Rack
|
|
2
|
-
class MiniProfiler
|
|
3
|
-
|
|
4
|
-
# This class acts as a proxy to the Body so that we can
|
|
5
|
-
# safely append to the end without knowing about the internals
|
|
6
|
-
# of the body class.
|
|
7
|
-
class BodyAddProxy
|
|
8
|
-
def initialize(body, additional_text)
|
|
9
|
-
@body = body
|
|
10
|
-
@additional_text = additional_text
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def respond_to?(*args)
|
|
14
|
-
super or @body.respond_to?(*args)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def method_missing(*args, &block)
|
|
18
|
-
@body.__send__(*args, &block)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# In the case of to_str we don't want to use method_missing as it might avoid
|
|
22
|
-
# a call to each (such as in Rack::Test)
|
|
23
|
-
def to_str
|
|
24
|
-
result = ""
|
|
25
|
-
each {|token| result << token}
|
|
26
|
-
result
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def each(&block)
|
|
30
|
-
|
|
31
|
-
# In ruby 1.9 we don't support String#each
|
|
32
|
-
if @body.is_a?(String)
|
|
33
|
-
yield @body
|
|
34
|
-
else
|
|
35
|
-
@body.each(&block)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
yield @additional_text
|
|
39
|
-
self
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
end
|