speed_gun 0.0.4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Rakefile +6 -1
  6. data/lib/speed_gun/app/views/meter.html.slim +4 -9
  7. data/lib/speed_gun/config.rb +33 -42
  8. data/lib/speed_gun/event.rb +72 -0
  9. data/lib/speed_gun/middleware.rb +43 -43
  10. data/lib/speed_gun/profile.rb +102 -0
  11. data/lib/speed_gun/profiler/action_controller_profiler.rb +14 -0
  12. data/lib/speed_gun/profiler/action_view_profiler.rb +11 -0
  13. data/lib/speed_gun/profiler/active_record_profiler.rb +11 -0
  14. data/lib/speed_gun/profiler/active_support_notifications_profiler.rb +29 -0
  15. data/lib/speed_gun/profiler/rack_profiler.rb +7 -0
  16. data/lib/speed_gun/profiler.rb +11 -118
  17. data/lib/speed_gun/railtie.rb +7 -16
  18. data/lib/speed_gun/store/elastic_search_store.rb +64 -0
  19. data/lib/speed_gun/store/fluent_logger_store.rb +29 -0
  20. data/lib/speed_gun/store/memcache_store.rb +40 -0
  21. data/lib/speed_gun/store/memory_store.rb +23 -0
  22. data/lib/speed_gun/store/multiple_store.rb +23 -0
  23. data/lib/speed_gun/store/redis_store.rb +41 -0
  24. data/lib/speed_gun/store.rb +7 -3
  25. data/lib/speed_gun/template.rb +1 -1
  26. data/lib/speed_gun/version.rb +1 -1
  27. data/lib/speed_gun.rb +30 -39
  28. data/spec/lib/speed_gun/config_spec.rb +37 -0
  29. data/spec/lib/speed_gun/event_spec.rb +70 -0
  30. data/spec/lib/speed_gun/middleware_spec.rb +65 -0
  31. data/spec/lib/speed_gun/profile_spec.rb +41 -0
  32. data/spec/lib/speed_gun_spec.rb +52 -0
  33. data/spec/spec_helper.rb +9 -0
  34. data/spec/support/simplecov.rb +12 -0
  35. data/speed_gun.gemspec +10 -7
  36. metadata +102 -56
  37. data/app/assets/javascripts/browser.js +0 -83
  38. data/app/assets/javascripts/profiler.js +0 -45
  39. data/app/views/speed_gun/_meter.html.slim +0 -9
  40. data/lib/speed_gun/app/public/browser.js +0 -83
  41. data/lib/speed_gun/app/public/jquery-1.10.2.min.js +0 -6
  42. data/lib/speed_gun/app/public/profile.js +0 -5
  43. data/lib/speed_gun/app/public/profiler.js +0 -45
  44. data/lib/speed_gun/app/public/style.css +0 -170
  45. data/lib/speed_gun/app/views/profile.slim +0 -97
  46. data/lib/speed_gun/app.rb +0 -58
  47. data/lib/speed_gun/browser/navigation.rb +0 -23
  48. data/lib/speed_gun/browser/timing.rb +0 -92
  49. data/lib/speed_gun/browser.rb +0 -22
  50. data/lib/speed_gun/hook.rb +0 -25
  51. data/lib/speed_gun/profiler/action_controller.rb +0 -12
  52. data/lib/speed_gun/profiler/action_view.rb +0 -12
  53. data/lib/speed_gun/profiler/active_record.rb +0 -16
  54. data/lib/speed_gun/profiler/base.rb +0 -139
  55. data/lib/speed_gun/profiler/js.rb +0 -17
  56. data/lib/speed_gun/profiler/manual.rb +0 -14
  57. data/lib/speed_gun/profiler/rack.rb +0 -7
  58. data/lib/speed_gun/store/base.rb +0 -9
  59. data/lib/speed_gun/store/file.rb +0 -62
  60. data/lib/speed_gun/store/memcache.rb +0 -27
  61. data/lib/speed_gun/store/memory.rb +0 -22
  62. data/lib/speed_gun/store/redis.rb +0 -28
@@ -1,92 +0,0 @@
1
- require 'speed_gun/browser'
2
-
3
- class SpeedGun::Browser::Timing < Hash
4
- # rubocop:disable SymbolName
5
- ATTRIBUTES = [
6
- :navigationStart,
7
- :unloadEventStart,
8
- :unloadEventEnd,
9
- :redirectStart,
10
- :redirectEnd,
11
- :fetchStart,
12
- :domainLookupStart,
13
- :domainLookupEnd,
14
- :connectStart,
15
- :connectEnd,
16
- :secureConnectionStart,
17
- :requestStart,
18
- :responseStart,
19
- :responseEnd,
20
- :domLoading,
21
- :domInteractive,
22
- :domContentLoadedEventStart,
23
- :domContentLoadedEventEnd,
24
- :domComplete,
25
- :loadEventStart,
26
- :loadEventEnd,
27
- ]
28
- # rubocop:enable all
29
-
30
- class Timing
31
- def initialize(name, base, started_at, ended_at)
32
- @name = name
33
- @started_at = started_at - base
34
- @elapsed_time = ended_at - started_at
35
- end
36
- attr_reader :name, :started_at, :elapsed_time
37
- end
38
-
39
- def initialize(hash)
40
- hash.each_pair do |key, val|
41
- self[key.to_s.to_sym] = val.to_i
42
- end
43
- end
44
-
45
- ATTRIBUTES.each do |key|
46
- define_method(key) { self[key] }
47
- end
48
-
49
- def load_time
50
- loadEventEnd - navigationStart
51
- end
52
-
53
- # rubocop:disable MethodLength
54
- def timings
55
- @timings ||= [
56
- (
57
- if redirectStart > 0
58
- Timing.new('Redirect', navigationStart, redirectStart, redirectEnd)
59
- else
60
- nil
61
- end
62
- ),
63
- Timing.new('Fetch all', navigationStart, fetchStart, responseEnd),
64
- Timing.new(
65
- 'DNS Lookup', navigationStart, domainLookupStart, domainLookupEnd
66
- ),
67
- Timing.new(
68
- 'TCP Connecting', navigationStart, connectStart, connectEnd
69
- ),
70
- (
71
- if secureConnectionStart > 0
72
- Timing.new('SSL', navigationStart, secureConnectionStart, connectEnd)
73
- else
74
- nil
75
- end
76
- ),
77
- Timing.new('Request', navigationStart, requestStart, responseStart),
78
- Timing.new('Response', navigationStart, responseStart, responseEnd),
79
- Timing.new('Unload', navigationStart, unloadEventStart, unloadEventEnd),
80
- Timing.new('DOM Load', navigationStart, domLoading, domInteractive),
81
- Timing.new(
82
- 'DOMContentLoaded Event',
83
- navigationStart, domContentLoadedEventStart, domContentLoadedEventEnd
84
- ),
85
- Timing.new(
86
- 'Sub resources loading', navigationStart, domInteractive, domComplete
87
- ),
88
- Timing.new('Load Event', navigationStart, loadEventStart, loadEventEnd),
89
- ].reject { |timing| timing.nil? }
90
- end
91
- # rubocop:enable
92
- end
@@ -1,22 +0,0 @@
1
- require 'speed_gun'
2
- require 'useragent'
3
-
4
- class SpeedGun::Browser
5
- def initialize(hash)
6
- @user_agent = UserAgent.parse(hash['user_agent'] || '')
7
- @navigation = Navigation.new(hash['navigation'] || {})
8
- @timing = Timing.new(hash['timing'] || {})
9
- end
10
- attr_reader :user_agent, :navigation, :timing
11
-
12
- def as_msgpack(*args)
13
- {
14
- user_agent: @user_agent.to_s,
15
- navigation: @navigation,
16
- timing: @timing,
17
- }
18
- end
19
- end
20
-
21
- require 'speed_gun/browser/navigation'
22
- require 'speed_gun/browser/timing'
@@ -1,25 +0,0 @@
1
- require 'speed_gun'
2
-
3
- class SpeedGun::Hook
4
- HOOKS = []
5
-
6
- def self.inherited(klass)
7
- HOOKS.push(klass) unless HOOKS.include?(klass)
8
- end
9
-
10
- def self.invoke_all(profiler)
11
- HOOKS.each { |hook| hook.invoke(profiler) }
12
- end
13
-
14
- def self.invoke(profiler)
15
- new(profiler).invoke
16
- end
17
-
18
- def initialize(profiler)
19
- @profiler = profiler
20
- end
21
- attr_reader :profiler
22
-
23
- def invoke
24
- end
25
- end
@@ -1,12 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::ActionController < SpeedGun::Profiler::Base
4
- hook_method ::ActionController::Base, :process
5
-
6
- attr_reader :action_name
7
- alias_method :title, :action_name
8
-
9
- def before_profile(controller, action)
10
- @action_name = "#{controller.class.name}##{action}"
11
- end
12
- end
@@ -1,12 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::ActionView < SpeedGun::Profiler::Base
4
- hook_method ::ActionView::Template, :render
5
-
6
- attr_reader :template_path
7
- alias_method :title, :template_path
8
-
9
- def before_profile(action_view, *args)
10
- @template_path = action_view.instance_variable_get(:@virtual_path)
11
- end
12
- end
@@ -1,16 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::ActiveRecord < SpeedGun::Profiler::Base
4
- def title
5
- "#{@name}"
6
- end
7
-
8
- def html
9
- %Q{<pre class="sql">#{@sql}</pre>}
10
- end
11
-
12
- def before_profile(adapter, sql, name = nil)
13
- @sql = sql
14
- @name = name
15
- end
16
- end
@@ -1,139 +0,0 @@
1
- require 'speed_gun/profiler'
2
- require 'securerandom'
3
-
4
- class SpeedGun::Profiler::Base
5
- def self.label
6
- name.sub(/.*::/, '')
7
- end
8
-
9
- def self.profiler_type
10
- name\
11
- .sub(/.*::/, '')\
12
- .gsub(/(.)([A-Z])/) { |m| "#{$1}_#{$2.downcase}" }\
13
- .downcase\
14
- .to_sym
15
- end
16
-
17
- def self.inherited(klass)
18
- SpeedGun::Profiler::PROFILERS[klass.profiler_type] = klass
19
- end
20
-
21
- def self.hook_method(klass, method_name)
22
- without_profiling = "#{method_name}_withtout_profile".intern
23
- with_profiling = "#{method_name}_with_profile".intern
24
- return unless klass.send(:method_defined?, method_name)
25
- return if klass.send(:method_defined?, with_profiling)
26
-
27
- profiler = profiler_type
28
- klass.send(:alias_method, without_profiling, method_name)
29
- klass.send(:define_method, with_profiling) do |*args, &block|
30
- return send(without_profiling, *args, &block) unless SpeedGun.current
31
-
32
- profile_args = [self] + args
33
- SpeedGun.current.profile(profiler, *profile_args) do
34
- send(without_profiling, *args, &block)
35
- end
36
- end
37
- klass.send(:alias_method, method_name, with_profiling)
38
- end
39
-
40
- def self.load(data)
41
- data.delete('label')
42
- type = data.delete('type')
43
- profiler = SpeedGun::Profiler::PROFILERS[type.to_sym]
44
- profile = profiler.new
45
-
46
- data.each_pair do |key, val|
47
- profile.send(:instance_variable_set, :"@#{key}", val)
48
- end
49
-
50
- profile
51
- end
52
-
53
- def self.profile(profiler, *args, &block)
54
- profile = new
55
- profiler.profiles << profile
56
- profile.profile(*args, &block)
57
- end
58
-
59
- def initialize
60
- @id = SecureRandom.uuid
61
- @parent_profile_id = nil
62
- @elapsed_time = 0
63
- @backtrace = []
64
- end
65
- attr_reader :id, :elapsed_time, :parent_profile_id, :backtrace
66
-
67
- def title
68
- warn 'Override this method'
69
- end
70
-
71
- def html
72
- ''
73
- end
74
-
75
- def label
76
- self.class.label
77
- end
78
-
79
- def type
80
- self.class.profiler_type
81
- end
82
-
83
- def profile(*args, &block)
84
- @backtrace = cleanup_caller(caller(3))
85
- parent_profile = SpeedGun.current.now_profile
86
- SpeedGun.current.now_profile = self
87
- call_without_defined(:before_profile, *args, &block)
88
- result = measure(&block)
89
- call_without_defined(:after_profile, *args, &block)
90
- return result
91
- ensure
92
- SpeedGun.current.now_profile = parent_profile
93
- @parent_profile_id = parent_profile.id if parent_profile
94
- end
95
-
96
- def measure(&block)
97
- now = Time.now
98
- result = yield
99
- @elapsed_time = Time.now - now
100
-
101
- result
102
- end
103
-
104
- def as_msgpack(*args)
105
- hash = {}
106
- instance_variables.each do |key|
107
- unless key.to_s =~ /^\@_/
108
- hash[key.to_s.sub(/^\@/, '')] = instance_variable_get(key)
109
- end
110
- end
111
- hash['type'] = type.to_s
112
- hash['label'] = label
113
- hash['title'] = title
114
- hash
115
- end
116
-
117
- def to_msgpack(*args)
118
- as_msgpack(*args).to_msgpack(*args)
119
- end
120
-
121
- private
122
-
123
- def call_without_defined(method, *args)
124
- send(method, *args) if respond_to?(method)
125
- end
126
-
127
- def cleanup_caller(caller)
128
- backtraces = caller.map do |backtrace|
129
- backtrace.sub(SpeedGun.config.backtrace_remove, '')
130
- end
131
- backtraces.reject! do |backtrace|
132
- !SpeedGun.config.backtrace_includes.any? do |regexp|
133
- backtrace =~ regexp
134
- end
135
- end
136
-
137
- backtraces
138
- end
139
- end
@@ -1,17 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::Js < SpeedGun::Profiler::Base
4
- def self.profile(profiler, title, elapsed_time, backtrace)
5
- profile = new
6
- profiler.profiles << profile
7
- profile.save(title, elapsed_time, backtrace)
8
- end
9
-
10
- attr_reader :title
11
-
12
- def save(title, elapsed_time, backtrace)
13
- @title = title.to_s
14
- @elapsed_time = elapsed_time.to_i * 0.001
15
- @backtrace = backtrace
16
- end
17
- end
@@ -1,14 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::Manual < SpeedGun::Profiler::Base
4
- def self.label
5
- 'Manual'
6
- end
7
-
8
- attr_reader :title, :html
9
-
10
- def before_profile(title, html = '')
11
- @title = title
12
- @html = html
13
- end
14
- end
@@ -1,7 +0,0 @@
1
- require 'speed_gun/profiler/base'
2
-
3
- class SpeedGun::Profiler::Rack < SpeedGun::Profiler::Base
4
- def title
5
- 'Rack Total'
6
- end
7
- end
@@ -1,9 +0,0 @@
1
- require 'speed_gun'
2
-
3
- class SpeedGun::Store::Base
4
- def [](id)
5
- end
6
-
7
- def []=(id, value)
8
- end
9
- end
@@ -1,62 +0,0 @@
1
- require 'speed_gun/store/base'
2
- require 'fileutils'
3
-
4
- class SpeedGun::Store::File
5
- DEFAULT_PATH = '/tmp/speed_gun'
6
- DEFAULT_EXPIRES_IN_SECONDS = 60 * 60 * 24
7
- CLEANUP_INTERVAL = 60 * 60
8
-
9
- def initialize(options = {})
10
- @path = (options[:path] || DEFAULT_PATH).to_s
11
- @expires = options[:expires] || DEFAULT_EXPIRES_IN_SECONDS
12
- @lock = Mutex.new
13
-
14
- this = self
15
- Thread.new do
16
- begin
17
- while true
18
- this.cleanup
19
- sleep(CLEANUP_INTERVAL)
20
- end
21
- rescue
22
- end
23
- end
24
- end
25
-
26
- def [](id)
27
- @lock.synchronize {
28
- read(id) if exist?(id)
29
- }
30
- end
31
-
32
- def []=(id, val)
33
- @lock.synchronize {
34
- write(id, val)
35
- }
36
- end
37
-
38
- def cleanup
39
- @lock.synchronize {
40
- files = Dir.entries(@path)
41
- files.each do |file|
42
- file = File.join(@path, file)
43
- File.delete(file) if (Time.now - File.mtime(file)) > @expires
44
- end
45
- }
46
- end
47
-
48
- private
49
-
50
- def read(id)
51
- File.open(File.join(@path, id), 'rb') { |f| f.read }
52
- end
53
-
54
- def write(id, val)
55
- FileUtils.mkdir_p(@path)
56
- File.open(File.join(@path, id), 'wb+') { |f| f.write(val) }
57
- end
58
-
59
- def exist?(id)
60
- File.exist?(File.join(@path, id))
61
- end
62
- end
@@ -1,27 +0,0 @@
1
- require 'speed_gun/store/base'
2
-
3
- class SpeedGun::Store::Memcache
4
- DEFAULT_PREFIX = 'speed-gun-'
5
- DEFAULT_EXPIRES_IN_SECONDS = 60 * 60 * 24
6
-
7
- def initialize(options = {})
8
- @prefix = options[:prefix] || DEFAULT_PREFIX
9
- @client = options[:client] || default_dalli
10
- @expires = options[:expires] || DEFAULT_EXPIRES_IN_SECONDS
11
- end
12
-
13
- def [](id)
14
- @client.get("#{@prefix}#{id}")
15
- end
16
-
17
- def []=(id, val)
18
- @client.set("#{@prefix}#{id}", val, @expires)
19
- end
20
-
21
- private
22
-
23
- def default_dalli
24
- require 'dalli' unless defined?(Dalli)
25
- Dalli::Client.new
26
- end
27
- end
@@ -1,22 +0,0 @@
1
- require 'speed_gun/store/base'
2
-
3
- class SpeedGun::Store::Memory < SpeedGun::Store::Base
4
- DEFAULT_MAX_ENTRIES = 100
5
-
6
- def initialize(options = {})
7
- @max_entries = options[:max_entries] || DEFAULT_MAX_ENTRIES
8
- @store = {}
9
- @stored_list = []
10
- end
11
-
12
- def [](id)
13
- @store[id]
14
- end
15
-
16
- def []=(id, val)
17
- @store[id] = val
18
- @stored_list.push(id)
19
-
20
- @store.delete(@stored_list.shift) while @stored_list.length > @max_entries
21
- end
22
- end
@@ -1,28 +0,0 @@
1
- require 'speed_gun/store/base'
2
-
3
- class SpeedGun::Store::Redis
4
- DEFAULT_PREFIX = 'speed-gun-'
5
- DEFAULT_EXPIRES_IN_SECONDS = 60 * 60 * 24
6
-
7
- def initialize(options = {})
8
- @prefix = options[:prefix] || DEFAULT_PREFIX
9
- @client = options[:client] || default_redis(options)
10
- @expires = options[:expires] || DEFAULT_EXPIRES_IN_SECONDS
11
- end
12
-
13
- def [](id)
14
- @client.get("#{@prefix}#{id}")
15
- end
16
-
17
- def []=(id, val)
18
- @client.setex("#{@prefix}#{id}", val, @expires)
19
- end
20
-
21
- private
22
-
23
- def default_redis(args)
24
- require 'redis' unless defined? Redis
25
- Redis.new(args)
26
- end
27
- end
28
-