speed_gun 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rubocop.yml +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +161 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/javascripts/browser.js +65 -0
  9. data/app/assets/javascripts/profiler.js +45 -0
  10. data/app/views/speed_gun/_meter.html.slim +9 -0
  11. data/lib/speed_gun/app/public/browser.js +65 -0
  12. data/lib/speed_gun/app/public/jquery-1.10.2.min.js +6 -0
  13. data/lib/speed_gun/app/public/profile.js +5 -0
  14. data/lib/speed_gun/app/public/profiler.js +45 -0
  15. data/lib/speed_gun/app/public/style.css +170 -0
  16. data/lib/speed_gun/app/views/meter.html.slim +9 -0
  17. data/lib/speed_gun/app/views/profile.slim +97 -0
  18. data/lib/speed_gun/app.rb +58 -0
  19. data/lib/speed_gun/browser/navigation.rb +23 -0
  20. data/lib/speed_gun/browser/timing.rb +92 -0
  21. data/lib/speed_gun/browser.rb +22 -0
  22. data/lib/speed_gun/config.rb +59 -0
  23. data/lib/speed_gun/hook.rb +25 -0
  24. data/lib/speed_gun/middleware.rb +91 -0
  25. data/lib/speed_gun/profiler/action_controller.rb +12 -0
  26. data/lib/speed_gun/profiler/action_view.rb +12 -0
  27. data/lib/speed_gun/profiler/active_record.rb +16 -0
  28. data/lib/speed_gun/profiler/base.rb +139 -0
  29. data/lib/speed_gun/profiler/js.rb +17 -0
  30. data/lib/speed_gun/profiler/manual.rb +14 -0
  31. data/lib/speed_gun/profiler/rack.rb +7 -0
  32. data/lib/speed_gun/profiler.rb +124 -0
  33. data/lib/speed_gun/railtie.rb +33 -0
  34. data/lib/speed_gun/store/base.rb +9 -0
  35. data/lib/speed_gun/store/file.rb +62 -0
  36. data/lib/speed_gun/store/memcache.rb +27 -0
  37. data/lib/speed_gun/store/memory.rb +22 -0
  38. data/lib/speed_gun/store/redis.rb +28 -0
  39. data/lib/speed_gun/store.rb +6 -0
  40. data/lib/speed_gun/template.rb +15 -0
  41. data/lib/speed_gun/version.rb +3 -0
  42. data/lib/speed_gun.rb +52 -0
  43. data/speed_gun.gemspec +29 -0
  44. metadata +184 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b40c0f702aa3870e1ebe8d74a1f3a9eb2a1ca466
4
+ data.tar.gz: 738743cbdf2c13d04392d9e994327e7d5ec8adb6
5
+ SHA512:
6
+ metadata.gz: edf1b6096de4f1af119d765f674d4776b79c5646f0039dc17dc0e01cf486797a75eb7b08a6549246e897a0476aec656933f44395bda159069366ffe97a8b41b2
7
+ data.tar.gz: 1b6f3b24ea288632ab2d89101f1d9ee3e69b002051c8bff29a96cef42e90a4b64624643a018a4db8ae158f10986a39d0e6729a1d5b47b8473e83c668926f486a
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ Documentation:
2
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in speed_gun.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sho Kusano
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # SpeedGun
2
+
3
+ First, profile. Second, profile.
4
+
5
+ SpeedGun is a better web app profiler on Rails and Rack apps.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'speed_gun'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install speed_gun
20
+
21
+ ## Usage
22
+
23
+ ### Rails
24
+
25
+ You don't require settings in development.
26
+
27
+ In production. You should set `enable_if` and `authorize_proc` configs.
28
+
29
+ ### Sinatra
30
+
31
+ ```ruby
32
+ require 'speed_gun'
33
+
34
+ class MyApplication < Sinatra::Base
35
+ use SpeedGun::Middleware
36
+ end
37
+ ```
38
+
39
+ ## Profiling
40
+
41
+ ### Built-in Profilers
42
+
43
+ SpeedGun has built-in profilers.
44
+
45
+ - `SpeedGun::Profiler::ActionController`
46
+ - `SpeedGun::Profiler::ActionView`
47
+ - `SpeedGun::Profiler::ActiveRecord`
48
+ - `SpeedGun::Profiler::Rack`
49
+
50
+ these profilers don't need configuration.
51
+
52
+ ### Manual Profiling
53
+
54
+ If you want take profile manually. You can use `SpeedGun.profile` method.
55
+
56
+ ```ruby
57
+ SpeedGun.profile("MyProfile#method") do
58
+ my_profile.method()
59
+ end
60
+ ```
61
+
62
+ ### Javascript Profiling
63
+
64
+ SpeedGun is supporting profiling on javascript. You can use `speedGun.profile` or `speedGun.profileMethod`.
65
+
66
+ ```javascript
67
+ speedGun.profile("any title", function() { ... codes ...});
68
+
69
+ var object = { func: function() { ... codes ... } };
70
+ speedGun.profileMethod(object, "func", "any title");
71
+ ```
72
+
73
+ And SpeedGun collect browser informations.
74
+
75
+ - User Agent
76
+ - Perfomance API(if implemented)
77
+
78
+ ### Custom Profiler
79
+
80
+ You can create your custom profilers. a custom profiler require `title` method.
81
+
82
+ Some examples:
83
+
84
+ #### SimpleCustomProfiler
85
+
86
+ ```ruby
87
+ class SimpleCustomProfiler < SpeedGun::Profiler::Base
88
+ def title
89
+ 'simple'
90
+ end
91
+ end
92
+
93
+ SpeedGun.profile(:simple_custom_profiler) { ... }
94
+ ```
95
+
96
+ #### BeforeFilterProfiler
97
+
98
+ ```ruby
99
+ class BeforeFilerProfiler < SpeedGun::Profiler::Base
100
+ # `hook_method` is a helper of method profiling.
101
+ hook_method ApplicationControler, :some_filter
102
+ end
103
+
104
+ class ApplicationControler
105
+ def some_filer
106
+ ...
107
+ end
108
+ end
109
+ ```
110
+
111
+ #### ForceGCProfiler
112
+
113
+ ```ruby
114
+ class ForceGCProfiler < SpeedGun::Profiler::Base
115
+ # You can define profiler type name.
116
+ def self.type
117
+ :force_gc_profiler
118
+ end
119
+
120
+ # `#before_profile` is called on before profiling.
121
+ def before_profile
122
+ @before_gc_disable = GC.enable
123
+ GC.start
124
+ end
125
+
126
+ # `#after_profile` is called on after profiling.
127
+ def after_profile
128
+ GC.disable if @before_gc_disable
129
+ end
130
+ end
131
+
132
+ SpeedGun.profile(:force_gc_profiler) { ... }
133
+ ```
134
+
135
+ ## Store
136
+
137
+ SpeedGun store request informations(profiling, environments and browser infos). You can select store engines.
138
+
139
+ ### Built-in Stores
140
+
141
+ - `SpeedGun::Store::Memory` (default store engine on rack)
142
+ - `max_entries` option: Set number of max profile entries(default: 100)
143
+ - `SpeedGun::Store::File` (default store engine on rails)
144
+ - `path` option: Set stored path(default: `/tmp/speed_gun` or `Rails.root/tmp/speed_gun`)
145
+ - `expires` option: Set expires in seconds(default: 1 day)
146
+ - `SpeedGun::Store::Memcache` (before `require 'speed_gun/store/memcache'`)
147
+ - `client` option: Set memcache client instance(default: `Dalli::Clinet.new`)
148
+ - `prefix` option: Set prefix of your profile key(default: `'speed-gun-'`)
149
+ - `expires` option: Set expires in seconds(default: 1 day)
150
+ - `SpeedGun::Store::Redis` (before `require 'speed_gun/store/redis'`)
151
+ - `client` option: Set redis client instance(default: `Redis.new`)
152
+ - `prefix` option: Set prefix of your profile key(default: `'speed-gun-'`)
153
+ - `expires` option: Set expires in seconds(default: 1 day)
154
+
155
+ ### Custom Store
156
+
157
+ SpeedGun's store engines requires `[]` and `[]=` methods.
158
+
159
+ ## Contributing
160
+
161
+ Please pull-requests :octocat: <http://github.com/rosylilly/speed_gun>
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,65 @@
1
+ if(!window['speedGun']) { window.speedGun = {}; };
2
+
3
+ (function($) {
4
+ if(!$) { return }
5
+
6
+ speedGun.sendBrowserInfo = function() {
7
+ var data = {};
8
+ var p = window['performance'];
9
+
10
+ data.user_agent = navigator.userAgent;
11
+
12
+ if(p['navigation']) {
13
+ data.navigation = {
14
+ type: p.navigation.type,
15
+ redirect_count: p.navigation.redirectCount
16
+ };
17
+ }
18
+
19
+ if(p['timing']) {
20
+ var t = p.timing;
21
+ data.timing = {
22
+ navigationStart: t.navigationStart,
23
+ redirectStart: t.redirectStart,
24
+ unloadEventStart: t.unloadEventStart,
25
+ unloadEventEnd: t.unloadEventEnd,
26
+ redirectEnd: t.redirectEnd,
27
+ fetchStart: t.fetchStart,
28
+ domainLookupStart: t.domainLookupStart,
29
+ domainLookupEnd: t.domainLookupEnd,
30
+ connectStart: t.connectStart,
31
+ secureConnectionStart: t.secureConnectionStart,
32
+ connectEnd: t.connectEnd,
33
+ requestStart: t.requestStart,
34
+ responseStart: t.responseStart,
35
+ responseEnd: t.responseEnd,
36
+ domLoading: t.domLoading,
37
+ domInteractive: t.domInteractive,
38
+ domContentLoadedEventStart: t.domContentLoadedEventStart,
39
+ domContentLoadedEventEnd: t.domContentLoadedEventEnd,
40
+ domComplete: t.domComplete,
41
+ loadEventStart: t.loadEventStart,
42
+ loadEventEnd: t.loadEventEnd,
43
+ };
44
+ }
45
+
46
+ speedGun.send({ browser: data });
47
+ $('#speed_gun_total').text(
48
+ (t.domContentLoadedEventEnd - t.navigationStart).toString() + 'ms'
49
+ );
50
+ };
51
+
52
+ speedGun.send = function(data) {
53
+ $.post(speedGun.endpoint, data, function() {});
54
+ };
55
+
56
+ var loadedInterval = setInterval(function() {
57
+ if (performance.timing.loadEventEnd != 0) {
58
+ clearInterval(loadedInterval);
59
+
60
+ speedGun.id = $('#speed_gun').data('speed-gun-id');
61
+ speedGun.endpoint = $('#speed_gun').data('speed-gun-endpoint') + "/" + speedGun.id;
62
+ speedGun.sendBrowserInfo()
63
+ }
64
+ }, 100);
65
+ })(window['jQuery'] || window['Zepto']);
@@ -0,0 +1,45 @@
1
+ if(!window['speedGun']) { window.speedGun = {}; };
2
+ speedGun.enableConsoleProfile = !!(window['console'] && console['profile']);
3
+ speedGun.profileCount = 0;
4
+
5
+ speedGun.profile = function(title, func) {
6
+ speedGun.profileCount++;
7
+ if(!func) {
8
+ func = title;
9
+ title = undefined;
10
+ };
11
+ if(!title) {
12
+ title = "Speed Gun Profile #" + speedGun.profileCount;
13
+ };
14
+ var callstack = [];
15
+ var caller = arguments['callee'];
16
+ if(caller) {
17
+ while(caller) {
18
+ caller = caller['caller'];
19
+ if(caller) { callstack.push(caller.toString()); };
20
+ }
21
+ }
22
+ var before = +(new Date);
23
+ if(speedGun.enableConsoleProfile) { console.profile(title); };
24
+ ret = func();
25
+ if(speedGun.enableConsoleProfile) { console.profileEnd(title); };
26
+ var elapsedTime = (+(new Date)) - before;
27
+ if(speedGun['send']) {
28
+ speedGun.send(
29
+ { js: { title: title, elapsed_time: elapsedTime, backtrace: callstack } }
30
+ );
31
+ };
32
+ return ret;
33
+ };
34
+
35
+ speedGun.profileMethod = function(object, methodName, title) {
36
+ if(!title) { title = "#" + methodName; };
37
+ var method = object[methodName];
38
+ var func = function() {
39
+ var args = arguments;
40
+ return speedGun.profile(title, function() {
41
+ return method.apply(object, args);
42
+ });
43
+ };
44
+ object[methodName] = func;
45
+ }
@@ -0,0 +1,9 @@
1
+ #speed_gun(data-speed-gun-endpoint="#{SpeedGun.config.prefix}/profile" data-speed-gun-id="#{SpeedGun.current.id}" data-rack-ms="#{SpeedGun.current.profiles.first.elapsed_time * 1000}")
2
+ - if SpeedGun.config.show_button?
3
+ #speed_gun_button(style="position: fixed; bottom: 10px; right: 10px;")
4
+ a#toggle_speed_gun(href="#{File.join(SpeedGun.config.prefix, 'profile', SpeedGun.current.id)}" target="_blank" style="display: block; padding: 2px 5px; font-size: 9px; line-height: 2; box-shadow: 0 0 2px #333; background-color: #fff; color: #333; text-decoration: none; border-radius: 3px;")
5
+ span#speed_gun_total(style="vertical-align: middle;")
6
+ - unless SpeedGun.config.no_include_jquery?
7
+ script(type="text/javascript" src="#{SpeedGun.config.prefix}/jquery-1.10.2.min.js")
8
+ script(type="text/javascript" src="#{SpeedGun.config.prefix}/browser.js")
9
+ script(type="text/javascript" src="#{SpeedGun.config.prefix}/profiler.js")
@@ -0,0 +1,65 @@
1
+ if(!window['speedGun']) { window.speedGun = {}; };
2
+
3
+ (function($) {
4
+ if(!$) { return }
5
+
6
+ speedGun.sendBrowserInfo = function() {
7
+ var data = {};
8
+ var p = window['performance'];
9
+
10
+ data.user_agent = navigator.userAgent;
11
+
12
+ if(p['navigation']) {
13
+ data.navigation = {
14
+ type: p.navigation.type,
15
+ redirect_count: p.navigation.redirectCount
16
+ };
17
+ }
18
+
19
+ if(p['timing']) {
20
+ var t = p.timing;
21
+ data.timing = {
22
+ navigationStart: t.navigationStart,
23
+ redirectStart: t.redirectStart,
24
+ unloadEventStart: t.unloadEventStart,
25
+ unloadEventEnd: t.unloadEventEnd,
26
+ redirectEnd: t.redirectEnd,
27
+ fetchStart: t.fetchStart,
28
+ domainLookupStart: t.domainLookupStart,
29
+ domainLookupEnd: t.domainLookupEnd,
30
+ connectStart: t.connectStart,
31
+ secureConnectionStart: t.secureConnectionStart,
32
+ connectEnd: t.connectEnd,
33
+ requestStart: t.requestStart,
34
+ responseStart: t.responseStart,
35
+ responseEnd: t.responseEnd,
36
+ domLoading: t.domLoading,
37
+ domInteractive: t.domInteractive,
38
+ domContentLoadedEventStart: t.domContentLoadedEventStart,
39
+ domContentLoadedEventEnd: t.domContentLoadedEventEnd,
40
+ domComplete: t.domComplete,
41
+ loadEventStart: t.loadEventStart,
42
+ loadEventEnd: t.loadEventEnd,
43
+ };
44
+ }
45
+
46
+ speedGun.send({ browser: data });
47
+ $('#speed_gun_total').text(
48
+ (t.domContentLoadedEventEnd - t.navigationStart).toString() + 'ms'
49
+ );
50
+ };
51
+
52
+ speedGun.send = function(data) {
53
+ $.post(speedGun.endpoint, data, function() {});
54
+ };
55
+
56
+ var loadedInterval = setInterval(function() {
57
+ if (performance.timing.loadEventEnd != 0) {
58
+ clearInterval(loadedInterval);
59
+
60
+ speedGun.id = $('#speed_gun').data('speed-gun-id');
61
+ speedGun.endpoint = $('#speed_gun').data('speed-gun-endpoint') + "/" + speedGun.id;
62
+ speedGun.sendBrowserInfo()
63
+ }
64
+ }, 100);
65
+ })(window['jQuery'] || window['Zepto']);