rack-mini-profiler 0.1.5 → 0.1.10

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 CHANGED
@@ -24,3 +24,23 @@
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
41
+
42
+ 7-August-2012 - Sam
43
+
44
+ * Added option to disable profiler for the current session (pp=disable / pp=enable)
45
+ * yajl compatability contributed by Sven Riedel
46
+
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
 
@@ -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;}
@@ -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
+ ;
@@ -1,4 +1,4 @@
1
- .box-shadow(@dx, @dy, @radius, @color) {
1
+ .box-shadow(@dx, @dy, @radius, @color) {
2
2
  -moz-box-shadow: @dx @dy @radius @color;
3
3
  -webkit-box-shadow: @dx @dy @radius @color;
4
4
  box-shadow: @dx @dy @radius @color;
@@ -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
- self['RedirectCount'] = env['rack.request.form_hash']['clientPerformance']['navigation']['redirectCount']
71
- self['Timings'] = timings
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
 
@@ -14,7 +14,7 @@ module Rack
14
14
 
15
15
  attr_accessor :auto_inject, :base_url_path, :pre_authorize_cb, :position,
16
16
  :backtrace_remove, :backtrace_filter, :skip_schema_queries,
17
- :storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode
17
+ :storage, :user_provider, :storage_instance, :storage_options, :skip_paths, :authorization_mode, :use_existing_jquery
18
18
 
19
19
  def self.default
20
20
  new.instance_eval {
@@ -30,6 +30,7 @@ module Rack
30
30
  @storage = MiniProfiler::MemoryStore
31
31
  @user_provider = Proc.new{|env| Rack::Request.new(env).ip}
32
32
  @authorization_mode = :allow_all
33
+ @use_existing_jquery = false
33
34
  self
34
35
  }
35
36
  end
@@ -16,7 +16,7 @@ module Rack
16
16
  "Level" => 0,
17
17
  "User" => "unknown user",
18
18
  "HasUserViewed" => false,
19
- "ClientTimings" => ClientTimerStruct.new,
19
+ "ClientTimings" => nil,
20
20
  "DurationMilliseconds" => 0,
21
21
  "HasTrivialTimings" => true,
22
22
  "HasAllTrivialTimigs" => false,
@@ -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 = 'rZlycOOTnzxZvxTmFuOEV0dSmu4P5m5bLrCtwJHVXPA=A'.freeze
21
+ VERSION = '104'.freeze
23
22
 
24
23
  class << self
25
24
 
@@ -64,11 +63,26 @@ module Rack
64
63
 
65
64
  # remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
66
65
  def remove_profiling_cookie(headers)
67
- Rack::Utils.delete_cookie_header!(headers, '__profilin')
66
+ Rack::Utils.set_cookie_header!(headers, '__profilin', :value => 'notstylin', :path => '/')
68
67
  end
69
68
 
70
69
  def set_profiling_cookie(headers)
71
- Rack::Utils.set_cookie_header!(headers, '__profilin', 'stylin')
70
+ Rack::Utils.set_cookie_header!(headers, '__profilin', :value => 'stylin', :path => '/')
71
+ end
72
+
73
+ # user has the mini profiler cookie, only used when config.authorization_mode == :whitelist
74
+ def has_disable_profiling_cookie?(env)
75
+ env['HTTP_COOKIE'] && env['HTTP_COOKIE'].include?("__profilin_disable=stylin")
76
+ end
77
+
78
+ # remove the mini profiler cookie, only used when config.authorization_mode == :whitelist
79
+ def remove_disable_profiling_cookie(headers)
80
+ #something is odd with delete_cookie_header
81
+ Rack::Utils.set_cookie_header!(headers, '__profilin_disable', :value => 'notstylin', :path => '/')
82
+ end
83
+
84
+ def set_disable_profiling_cookie(headers)
85
+ Rack::Utils.set_cookie_header!(headers, '__profilin_disable', :value => 'stylin', :path => '/')
72
86
  end
73
87
 
74
88
  def create_current(env={}, options={})
@@ -101,8 +115,9 @@ module Rack
101
115
  @app = app
102
116
  @config.base_url_path << "/" unless @config.base_url_path.end_with? "/"
103
117
  unless @config.storage_instance
104
- @storage = @config.storage_instance = @config.storage.new(@config.storage_options)
118
+ @config.storage_instance = @config.storage.new(@config.storage_options)
105
119
  end
120
+ @storage = @config.storage_instance
106
121
  end
107
122
 
108
123
  def user(env)
@@ -118,7 +133,7 @@ module Rack
118
133
  return [404, {}, ["Request not found: #{request['id']} - user #{user(env)}"]]
119
134
  end
120
135
  unless page_struct['HasUserViewed']
121
- page_struct['ClientTimings'].init_from_form_data(env, page_struct)
136
+ page_struct['ClientTimings'] = ClientTimerStruct.init_from_form_data(env, page_struct)
122
137
  page_struct['HasUserViewed'] = true
123
138
  @storage.save(page_struct)
124
139
  @storage.set_viewed(user(env), id)
@@ -151,8 +166,17 @@ module Rack
151
166
  return [404, {}, ["Not found"]] unless ::File.exists? full_path
152
167
  f = Rack::File.new nil
153
168
  f.path = full_path
154
- f.cache_control = "max-age:86400"
155
- f.serving env
169
+
170
+ begin
171
+ f.cache_control = "max-age:86400"
172
+ f.serving env
173
+ rescue
174
+ # old versions of rack have a different api
175
+ status, headers, body = f.serving
176
+ headers.merge! 'Cache-Control' => "max-age:86400"
177
+ [status, headers, body]
178
+ end
179
+
156
180
  end
157
181
 
158
182
 
@@ -172,11 +196,12 @@ module Rack
172
196
 
173
197
  def call(env)
174
198
  status = headers = body = nil
199
+ query_string = env['QUERY_STRING']
175
200
  path = env['PATH_INFO']
176
201
 
177
202
  skip_it = (@config.pre_authorize_cb && !@config.pre_authorize_cb.call(env)) ||
178
203
  (@config.skip_paths && @config.skip_paths.any?{ |p| path[0,p.length] == p}) ||
179
- env["QUERY_STRING"] =~ /pp=skip/
204
+ query_string =~ /pp=skip/
180
205
 
181
206
  has_profiling_cookie = MiniProfiler.has_profiling_cookie?(env)
182
207
 
@@ -189,13 +214,29 @@ module Rack
189
214
  end
190
215
 
191
216
  # handle all /mini-profiler requests here
192
- return serve_html(env) if env['PATH_INFO'].start_with? @config.base_url_path
217
+ return serve_html(env) if path.start_with? @config.base_url_path
218
+
219
+ has_disable_cookie = MiniProfiler.has_disable_profiling_cookie?(env)
220
+ # manual session disable / enable
221
+ if query_string =~ /pp=disable/ || has_disable_cookie
222
+ skip_it = true
223
+ end
224
+
225
+ if query_string =~ /pp=enable/
226
+ skip_it = false
227
+ end
228
+
229
+ if skip_it
230
+ status,headers,body = @app.call(env)
231
+ MiniProfiler.set_disable_profiling_cookie(headers) unless has_disable_cookie
232
+ return [status,headers,body]
233
+ end
193
234
 
194
235
  MiniProfiler.create_current(env, @config)
195
236
  MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
196
- if env["QUERY_STRING"] =~ /pp=no-backtrace/
237
+ if query_string =~ /pp=no-backtrace/
197
238
  current.skip_backtrace = true
198
- elsif env["QUERY_STRING"] =~ /pp=full-backtrace/
239
+ elsif query_string =~ /pp=full-backtrace/
199
240
  current.full_backtrace = true
200
241
  end
201
242
 
@@ -203,7 +244,7 @@ module Rack
203
244
  quit_sampler = false
204
245
  backtraces = nil
205
246
  missing_stacktrace = false
206
- if env["QUERY_STRING"] =~ /pp=sample/
247
+ if query_string =~ /pp=sample/
207
248
  backtraces = []
208
249
  t = Thread.current
209
250
  Thread.new {
@@ -231,6 +272,9 @@ module Rack
231
272
  start = Time.now
232
273
  begin
233
274
  status,headers,body = @app.call(env)
275
+ if has_disable_cookie
276
+ MiniProfiler.remove_disable_profiling_cookie(headers)
277
+ end
234
278
  ensure
235
279
  if backtraces
236
280
  done_sampling = true
@@ -245,14 +289,14 @@ module Rack
245
289
  end
246
290
 
247
291
  return [status,headers,body] if skip_it
248
-
292
+
249
293
  # we must do this here, otherwise current[:discard] is not being properly treated
250
- if env["QUERY_STRING"] =~ /pp=env/
294
+ if query_string =~ /pp=env/
251
295
  body.close if body.respond_to? :close
252
296
  return dump_env env
253
297
  end
254
298
 
255
- if env["QUERY_STRING"] =~ /pp=help/
299
+ if query_string =~ /pp=help/
256
300
  body.close if body.respond_to? :close
257
301
  return help
258
302
  end
@@ -274,6 +318,12 @@ module Rack
274
318
  # inject headers, script
275
319
  if status == 200
276
320
 
321
+ # mini profiler is meddling with stuff, we can not cache cause we will get incorrect data
322
+ # Rack::ETag has already inserted some nonesense in the chain
323
+ headers.delete('ETag')
324
+ headers.delete('Date')
325
+ headers['Cache-Control'] = 'must-revalidate, private, max-age=0'
326
+
277
327
  # inject header
278
328
  if headers.is_a? Hash
279
329
  headers['X-MiniProfiler-Ids'] = ids_json(env)
@@ -283,21 +333,37 @@ module Rack
283
333
  if current.inject_js \
284
334
  && headers.has_key?('Content-Type') \
285
335
  && !headers['Content-Type'].match(/text\/html/).nil? then
286
- body = MiniProfiler::BodyAddProxy.new(body, self.get_profile_script(env))
336
+
337
+ response = Rack::Response.new([], status, headers)
338
+ script = self.get_profile_script(env)
339
+ if String === body
340
+ response.write inject(body,script)
341
+ else
342
+ body.each { |fragment| response.write inject(fragment, script) }
343
+ end
344
+ body.close if body.respond_to? :close
345
+ return response.finish
287
346
  end
288
347
  end
289
348
 
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
349
  [status, headers, body]
296
350
  ensure
297
351
  # Make sure this always happens
298
352
  current = nil
299
353
  end
300
354
 
355
+ def inject(fragment, script)
356
+ fragment.sub(/<\/body>/i) do
357
+ # if for whatever crazy reason we dont get a utf string,
358
+ # just force the encoding, no utf in the mp scripts anyway
359
+ if script.respond_to?(:encoding) && script.respond_to?(:force_encoding)
360
+ (script + "</body>").force_encoding(fragment.encoding)
361
+ else
362
+ script + "</body>"
363
+ end
364
+ end
365
+ end
366
+
301
367
  def dump_env(env)
302
368
  headers = {'Content-Type' => 'text/plain'}
303
369
  body = ""
@@ -317,6 +383,8 @@ module Rack
317
383
  pp=no-backtrace : don't collect stack traces from all the SQL executed
318
384
  pp=full-backtrace : enable full backtrace for SQL executed
319
385
  pp=sample : sample stack traces and return a report isolating heavy usage (requires the stacktrace gem)
386
+ pp=disable : disable profiling for this session
387
+ pp=enable : enable profiling for this session (if previously disabled)
320
388
  "
321
389
  if (category == :stacktrace)
322
390
  body = "pp=stacktrace requires the stacktrace gem - add gem 'stacktrace' to your Gemfile"
@@ -380,7 +448,7 @@ module Rack
380
448
  showControls = false
381
449
  currentId = current.page_struct["Id"]
382
450
  authorized = true
383
- useExistingjQuery = false
451
+ useExistingjQuery = @config.use_existing_jquery
384
452
  # TODO : cache this snippet
385
453
  script = IO.read(::File.expand_path('../html/profile_handler.js', ::File.dirname(__FILE__)))
386
454
  # replace the variables
@@ -39,9 +39,14 @@ module Rack
39
39
 
40
40
  me = self
41
41
  Thread.new do
42
- while true do
43
- me.cleanup_cache if MiniProfiler.instance
44
- sleep(3600)
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 {
@@ -52,10 +52,6 @@ module Rack
52
52
  }
53
53
  end
54
54
 
55
-
56
- private
57
-
58
-
59
55
  def cleanup_cache
60
56
  expire_older_than = ((Time.now.to_f - MiniProfiler::MemoryStore::EXPIRE_TIMER_CACHE) * 1000).to_i
61
57
  @timer_struct_lock.synchronize {
@@ -22,7 +22,12 @@ module Rack
22
22
  end
23
23
 
24
24
  def to_json(*a)
25
- ::JSON.generate(@attributes, a[0])
25
+ if a[0] == nil
26
+ # YAJL doesnt like nil as options
27
+ ::JSON.generate( @attributes )
28
+ else
29
+ ::JSON.generate(@attributes, a[0])
30
+ end
26
31
  end
27
32
 
28
33
  end
@@ -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
- Dir::mkdir(tmp) unless File.exists?(tmp)
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
@@ -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
- module Rack
138
- class MiniProfiler
139
- module ActiveRecordInstrumentation
140
- def self.included(instrumented_class)
141
- instrumented_class.class_eval do
142
- unless instrumented_class.method_defined?(:log_without_miniprofiler)
143
- alias_method :log_without_miniprofiler, :log
144
- alias_method :log, :log_with_miniprofiler
145
- protected :log
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
- def log_with_miniprofiler(*args, &block)
151
- current = ::Rack::MiniProfiler.current
152
- return log_without_miniprofiler(*args, &block) unless current
157
+ def log_with_miniprofiler(*args, &block)
158
+ current = ::Rack::MiniProfiler.current
159
+ return log_without_miniprofiler(*args, &block) unless current
153
160
 
154
- sql, name, binds = args
155
- t0 = Time.now
156
- rval = log_without_miniprofiler(*args, &block)
157
-
158
- # Don't log schema queries if the option is set
159
- return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
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
- elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
162
- Rack::MiniProfiler.record_sql(sql, elapsed_time)
163
- rval
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
- def self.insert_instrumentation
169
- ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
170
- include ::Rack::MiniProfiler::ActiveRecordInstrumentation
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
- if defined?(::Rails) && !SqlPatches.patched?
175
- insert_instrumentation
181
+ if defined?(::Rails) && !SqlPatches.patched?
182
+ insert_instrumentation
183
+ end
176
184
  end
177
185
  end
178
-
@@ -1,6 +1,6 @@
1
- require File.expand_path('mini_profiler/profiler', File.dirname(__FILE__) )
2
- require File.expand_path('patches/sql_patches', File.dirname(__FILE__) )
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 File.expand_path('mini_profiler_rails/railtie', File.dirname(__FILE__) )
5
+ require 'mini_profiler_rails/railtie'
6
6
  end
@@ -1,9 +1,8 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack-mini-profiler"
3
- s.version = "0.1.5"
3
+ s.version = "0.1.10"
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.5
4
+ version: 0.1.10
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-04-02 00:00:00.000000000 Z
14
+ date: 2012-08-07 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: -495765037
133
+ hash: -296105007
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: -495765037
142
+ hash: -296105007
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