memory_tracker 1.0.0

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.
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module MemoryTracker
4
+ describe MemoryTracker do
5
+ before :each do
6
+ @env = double('env')
7
+ allow(@env).to receive(:controller) { 'Boat' }
8
+ allow(@env).to receive(:action) { 'sail' }
9
+
10
+ @memory_store = double('memory_store')
11
+ @logfile_store = double('logfile_store')
12
+ @tracker = MemoryTracker.instance
13
+ @tracker.stores.clear
14
+ end
15
+
16
+ it 'should be a singleton' do
17
+ lambda { MemoryTracker.new }.should raise_error(NoMethodError)
18
+ end
19
+
20
+ it 'should push requests to all stores' do
21
+ allow(@memory_store).to receive(:name) { :memory }
22
+ allow(@logfile_store).to receive(:name) { :gcstat_logfile }
23
+ expect(@memory_store).to receive(:push)
24
+ expect(@logfile_store).to receive(:push)
25
+
26
+ @tracker.add_store(@memory_store)
27
+ @tracker.add_store(@logfile_store)
28
+
29
+ @tracker.start_request(@env)
30
+ @tracker.end_request
31
+ end
32
+
33
+ it 'should populate livestore' do
34
+ @tracker.add_store(Stores::InMemoryStore::Manager.new)
35
+
36
+ Request.stub(:rss) { 100 }
37
+ @tracker.start_request(@env)
38
+ Request.stub(:rss) { 108 }
39
+ @tracker.end_request
40
+
41
+ stats = @tracker.stats(:memory)
42
+ stats.count('Boat', 'sail').should == 1
43
+ stats.count('Boat', 'moor').should == 0
44
+ stats.fetch('Boat', 'sail', :rss).should == 8
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ module MemoryTracker
4
+ describe Request do
5
+ before :each do
6
+ @env = double('env')
7
+ @request = Request.new(@env)
8
+ end
9
+
10
+ it 'should initalize start_gcstat' do
11
+ @request.start_gcstat.should be_a(GcStat)
12
+ @request.start_gcstat.stats.keys.should include :rss
13
+ @request.start_gcstat.stats.keys.should include :vsize
14
+ end
15
+
16
+ it 'should have a controller' do
17
+ allow(@env).to receive(:controller) { 'Foo' }
18
+ allow(@env).to receive(:action) { :bar }
19
+ @request.controller.should == 'Foo'
20
+ @request.action.should == :bar
21
+ end
22
+
23
+ context :close do
24
+ it 'should initialize end_gcstat' do
25
+ @request.close
26
+ @request.end_gcstat.should be_a(GcStat)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module MemoryTracker
2
+ module Stores
3
+ describe GcstatLogfileStore do
4
+ before :each do
5
+ logger_class = double("logger_class")
6
+ allow(logger_class).to receive(:new)
7
+ @logstore = GcstatLogfileStore.new logger_class, "foo/log"
8
+ end
9
+
10
+ it 'implements the store role' do
11
+ @logstore.should respond_to(:name)
12
+ @logstore.should respond_to(:push)
13
+ @logstore.should respond_to(:stats)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,161 @@
1
+ require 'spec_helper'
2
+
3
+ def sample_stats(factor=1)
4
+ base = {
5
+ :rss => 1,
6
+ :vsize => 2,
7
+ :count => 4,
8
+ :heap_used => 86,
9
+ :heap_length => 138,
10
+ :heap_increment =>52,
11
+ :heap_live_num =>34768,
12
+ :heap_free_num =>22099,
13
+ :heap_final_num =>0,
14
+ :total_allocated_object =>68540,
15
+ :total_freed_object =>33772
16
+ }
17
+ sample = {}
18
+ base.each { |k,v| sample[k] = v * factor }
19
+ sample
20
+ end
21
+
22
+ def stub_gcstat_delta(controller, action, factor=1)
23
+ allow(@env).to receive(:controller) { controller }
24
+ allow(@env).to receive(:action) { action }
25
+ MemoryTracker::GcStatDelta.any_instance.stub(:stats) { sample_stats(factor) }
26
+ end
27
+
28
+ module MemoryTracker
29
+ module Stores
30
+ module InMemoryStore
31
+ describe Manager do
32
+ def start_time
33
+ Time.new(2013,01,01,0,0,0)
34
+ end
35
+
36
+ before :each do
37
+ @env = double('env')
38
+ end
39
+
40
+ it 'should respond to name' do
41
+ manager = Manager.new(60)
42
+ manager.should respond_to(:name)
43
+ end
44
+
45
+ it 'should return stats from older window' do
46
+ Time.stub(:now).and_return(start_time)
47
+ manager = Manager.new(60)
48
+ request = Request.new(@env)
49
+ stub_gcstat_delta('Boat', 'sail')
50
+ manager.push(request.close)
51
+ Time.stub(:now).and_return(start_time + 10)
52
+ request = Request.new(@env)
53
+ stub_gcstat_delta('Car', 'drive', 2)
54
+ manager.push(request.close)
55
+ Time.stub(:now).and_return(start_time + 40)
56
+ request = Request.new(@env)
57
+ stub_gcstat_delta('Boat', 'sail', 3)
58
+ manager.push(request.close)
59
+
60
+ stats = manager.stats
61
+ stats.fetch('Boat', 'sail', :rss).should == 4
62
+ stats.fetch('Car', 'drive', :rss).should == 2
63
+ end
64
+
65
+ it 'should rotate windows' do
66
+ Time.stub(:now).and_return(start_time)
67
+ manager = Manager.new(60)
68
+ request = Request.new(@env)
69
+ stub_gcstat_delta('Boat', 'sail')
70
+ manager.push(request.close)
71
+ Time.stub(:now).and_return(start_time + 10)
72
+ request = Request.new(@env)
73
+ stub_gcstat_delta('Car', 'drive', 2)
74
+ manager.push(request.close)
75
+ Time.stub(:now).and_return(start_time + 40)
76
+ request = Request.new(@env)
77
+ stub_gcstat_delta('Boat', 'sail', 3)
78
+ manager.push(request.close)
79
+ Time.stub(:now).and_return(start_time + 70)
80
+
81
+ stats = manager.stats
82
+ stats.fetch('Boat', 'sail', :rss).should == 3
83
+ stats.fetch('Car', 'drive', :rss).should be_nil
84
+ end
85
+ end
86
+
87
+ describe StatInterval do
88
+
89
+ before :each do
90
+ @interval = InMemoryStore::StatInterval.new(Time.now, 5*60)
91
+ @env = double('env')
92
+ end
93
+
94
+ it 'should accept requests' do
95
+ env = double('env')
96
+ request = Request.new(env)
97
+ allow(env).to receive(:controller) { :Foo }
98
+ allow(env).to receive(:action) { :bar }
99
+ request.close
100
+ request.controller.should == :Foo
101
+ request.action.should == :bar
102
+ @interval.push(request)
103
+ end
104
+
105
+ it 'should accumulate one request' do
106
+ req1 = Request.new(@env)
107
+ req1.close
108
+ stub_gcstat_delta('Boat', 'sail')
109
+ @interval.push(req1)
110
+ @interval.stats.should be_a(Stats)
111
+ @interval.stats.fetch('Boat', 'sail', :rss).should == 1
112
+ end
113
+
114
+ it 'should accumulate several requests' do
115
+ req1 = Request.new(@env)
116
+ req1.close
117
+ stub_gcstat_delta('Boat', 'sail')
118
+ @interval.push(req1)
119
+ req2 = Request.new(@env)
120
+ req2.close
121
+ stub_gcstat_delta('Boat', 'sail', 2)
122
+ @interval.push(req2)
123
+ req3 = Request.new(@env)
124
+ req3.close
125
+ stub_gcstat_delta('Boat', 'moor', 5)
126
+ @interval.push(req3)
127
+ req4 = Request.new(@env)
128
+ req4.close
129
+ stub_gcstat_delta('Car', 'drive', 1)
130
+ @interval.push(req4)
131
+
132
+ stats = @interval.stats
133
+ stats.count('Boat', 'sail').should == 2
134
+ stats.fetch('Boat', 'sail', :rss).should == 3
135
+ stats.fetch('Boat', 'sail', :count).should == 12
136
+ stats.count('Boat', 'moor').should == 1
137
+ stats.fetch('Boat', 'moor', :rss).should == 5
138
+ stats.fetch('Boat', 'moor', :count).should == 20
139
+ stats.count('Car', 'drive').should == 1
140
+ stats.fetch('Car', 'drive', :rss).should == 1
141
+ stats.fetch('Car', 'drive', :count).should == 4
142
+ end
143
+
144
+ it 'should be enumerable' do
145
+ req1 = Request.new(@env)
146
+ req1.close
147
+ stub_gcstat_delta('Boat', 'sail')
148
+ @interval.push(req1)
149
+ req2 = Request.new(@env)
150
+ req2.close
151
+ stub_gcstat_delta('Boat', 'moor')
152
+ @interval.push(req2)
153
+
154
+ @interval.size.should == 2
155
+ @interval.to_a.should include(['Boat', 'sail', { :num => 1, :gcstat => sample_stats} ])
156
+ @interval.to_a.should include(['Boat', 'moor', { :num => 1, :gcstat => sample_stats} ])
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,17 @@
1
+ module MemoryTracker
2
+ module Stores
3
+ describe UrlLogfileStore do
4
+ before :each do
5
+ logger_class = double("logger_class")
6
+ allow(logger_class).to receive(:new)
7
+ @logstore = UrlLogfileStore.new logger_class, "foo/log"
8
+ end
9
+
10
+ it 'implements the store role' do
11
+ @logstore.should respond_to(:name)
12
+ @logstore.should respond_to(:push)
13
+ @logstore.should respond_to(:stats)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'singleton'
5
+
6
+ require 'rspec'
7
+ require 'sys/proctable'
8
+ require 'memory_tracker'
9
+ require 'memory_tracker/gc_stat'
10
+ require 'memory_tracker/request'
11
+ require 'memory_tracker/memory_tracker'
12
+ require 'memory_tracker/stores/in_memory_store'
13
+ require 'memory_tracker/stores/gcstat_logfile_store'
14
+ require 'memory_tracker/stores/url_logfile_store'
15
+
16
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
17
+ ENV["RAILS_ENV"] ||= 'test'
18
+ # require 'rspec/rails'
19
+ # require 'rspec/mocks/standalone'
20
+
21
+ # Requires supporting ruby files with custom matchers and macros, etc,
22
+ # in spec/support/ and its subdirectories.
23
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
24
+
25
+
26
+ RSpec.configure do |config|
27
+ # == Mock Framework
28
+ #
29
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
30
+ #
31
+ # config.mock_with :mocha
32
+ # config.mock_with :flexmock
33
+ # config.mock_with :rr
34
+ # config.mock_with :rspec
35
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: memory_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Philippe Le Rohellec
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sys-proctable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: debugger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: jeweler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.7
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 1.8.7
97
+ - !ruby/object:Gem::Dependency
98
+ name: sys-proctable
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Collect and analyze memory usage data for each individual Rails action
112
+ controller.
113
+ email: philippe@lerohellec.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files:
117
+ - LICENSE.txt
118
+ - README.rdoc
119
+ files:
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - LICENSE.txt
123
+ - README.rdoc
124
+ - Rakefile
125
+ - VERSION
126
+ - app/controllers/memory_tracker/dashboards_controller.rb
127
+ - app/helpers/memory_tracker/dashboards_helper.rb
128
+ - app/views/layouts/memory_tracker.html.erb
129
+ - app/views/memory_tracker/dashboards/index.html.erb
130
+ - config/routes.rb
131
+ - docs/design.rb
132
+ - lib/memory_tracker.rb
133
+ - lib/memory_tracker/engine.rb
134
+ - lib/memory_tracker/env.rb
135
+ - lib/memory_tracker/gc_stat.rb
136
+ - lib/memory_tracker/memory_tracker.rb
137
+ - lib/memory_tracker/middleware.rb
138
+ - lib/memory_tracker/request.rb
139
+ - lib/memory_tracker/stores/gcstat_logfile_store.rb
140
+ - lib/memory_tracker/stores/in_memory_store.rb
141
+ - lib/memory_tracker/stores/url_logfile_store.rb
142
+ - memory_tracker.gemspec
143
+ - spec/lib/memory_tracker_spec.rb
144
+ - spec/lib/request_spec.rb
145
+ - spec/lib/stores/gcstat_logfile_store_spec.rb
146
+ - spec/lib/stores/in_memory_store_spec.rb
147
+ - spec/lib/stores/url_logfile_store_spec.rb
148
+ - spec/spec_helper.rb
149
+ homepage: http://github.com/plerohellec/memory_tracker
150
+ licenses:
151
+ - MIT
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - '>='
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.0.3
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Rails memory allocations tracker
173
+ test_files: []