speed_gun 0.0.4 → 1.0.0.rc1

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.
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
-