Skip to content

Commit 3d94f41

Browse files
committed
Replace vmstat gem with /proc reads
The vmstat gem is a native C extension with no Windows support (its build fails there), and it surfaced in an outdated-dependency audit. On the Linux ccng runtime all three values it provided are available directly from /proc, so the gem can be dropped from lib/vcap/stats.rb. Behaviour is preserved. vmstat's Linux backend reads /proc/meminfo, so: - memory_free_bytes = (Inactive + MemFree) * 1024 - memory_used_bytes = (MemTotal - Inactive - MemFree) * 1024 (equals vmstat's active+wired by conservation - the buckets sum to MemTotal) - cpu_load_average = first field of /proc/loadavg Verified against the live vmstat gem on a production CF API VM: 0.0% diff on both memory metrics, load average identical to rounding. Non-Linux dev machines (Mac/Windows) return 0, where these metrics have no consumer. Add a stats spec covering all three methods on both the Linux and non-Linux paths, which previously had no direct coverage.
1 parent 8547306 commit 3d94f41

4 files changed

Lines changed: 80 additions & 9 deletions

File tree

‎Gemfile‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ gem 'sinatra-contrib'
3131
gem 'statsd-instrument', '~> 3.11'
3232
gem 'talentbox-delayed_job_sequel', '~> 4.4.0'
3333
gem 'uri', '~> 1.1'
34-
gem 'vmstat', '~> 2.3'
3534

3635
# Rails Components
3736
gem 'actionpack', '~> 8.1.2'

‎Gemfile.lock‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@ GEM
419419
unicode-emoji (4.2.0)
420420
uri (1.1.1)
421421
useragent (0.16.11)
422-
vmstat (2.3.1)
423422
webmock (3.26.2)
424423
addressable (>= 2.8.0)
425424
crack (>= 0.3.2)
@@ -505,7 +504,6 @@ DEPENDENCIES
505504
talentbox-delayed_job_sequel (~> 4.4.0)
506505
timecop
507506
uri (~> 1.1)
508-
vmstat (~> 2.3)
509507
webmock (> 2.3.1)
510508
webrick (~> 1.9.2)
511509

‎lib/vcap/stats.rb‎

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
require 'vcap/pid_file'
2-
require 'vmstat'
32

43
module VCAP
54
class Stats
@@ -16,21 +15,38 @@ def process_memory_bytes_and_cpu
1615
end
1716

1817
def memory_used_bytes
19-
mem = Vmstat.memory
20-
mem.active_bytes + mem.wired_bytes
18+
return 0 unless linux?
19+
20+
m = meminfo
21+
(m['MemTotal'] - m['Inactive'] - m['MemFree']) * 1024
2122
end
2223

2324
def memory_free_bytes
24-
mem = Vmstat.memory
25-
mem.inactive_bytes + mem.free_bytes
25+
return 0 unless linux?
26+
27+
m = meminfo
28+
(m['Inactive'] + m['MemFree']) * 1024
2629
end
2730

2831
def cpu_load_average
29-
Vmstat.load_average.one_minute
32+
return 0 unless linux?
33+
34+
File.read('/proc/loadavg').split.first.to_f
3035
end
3136

3237
private
3338

39+
def linux?
40+
RUBY_PLATFORM.match?(/linux/)
41+
end
42+
43+
def meminfo
44+
File.read('/proc/meminfo').each_line.with_object({}) do |line, h|
45+
k, v = line.split
46+
h[k.chomp(':')] = v.to_i if k && v
47+
end
48+
end
49+
3450
def ps_pid
3551
`ps -o rss=,pcpu= -p #{Process.pid}`
3652
end

‎spec/unit/lib/vcap/stats_spec.rb‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,62 @@
1313
expect(pcpu).to eq(17)
1414
end
1515
end
16+
17+
describe 'system metrics on Linux' do
18+
let(:meminfo) do
19+
<<~MEMINFO
20+
MemTotal: 16793990 kB
21+
MemFree: 10810368 kB
22+
MemAvailable: 13636608 kB
23+
Buffers: 455475 kB
24+
Cached: 2707660 kB
25+
Active: 920268 kB
26+
Inactive: 4609024 kB
27+
MEMINFO
28+
end
29+
let(:loadavg) { "1.37 1.21 1.05 2/512 12345\n" }
30+
31+
before do
32+
allow(VCAP::Stats).to receive(:linux?).and_return(true)
33+
allow(File).to receive(:read).and_call_original
34+
allow(File).to receive(:read).with('/proc/meminfo').and_return(meminfo)
35+
allow(File).to receive(:read).with('/proc/loadavg').and_return(loadavg)
36+
end
37+
38+
describe '#memory_free_bytes' do
39+
it 'returns (Inactive + MemFree) in bytes' do
40+
expect(VCAP::Stats.memory_free_bytes).to eq((4_609_024 + 10_810_368) * 1024)
41+
end
42+
end
43+
44+
describe '#memory_used_bytes' do
45+
it 'returns (MemTotal - Inactive - MemFree) in bytes' do
46+
expect(VCAP::Stats.memory_used_bytes).to eq((16_793_990 - 4_609_024 - 10_810_368) * 1024)
47+
end
48+
end
49+
50+
describe '#cpu_load_average' do
51+
it 'returns the one-minute load as a float' do
52+
expect(VCAP::Stats.cpu_load_average).to eq(1.37)
53+
end
54+
end
55+
end
56+
57+
describe 'system metrics on non-Linux' do
58+
before do
59+
allow(VCAP::Stats).to receive(:linux?).and_return(false)
60+
end
61+
62+
it 'returns 0 for memory_used_bytes' do
63+
expect(VCAP::Stats.memory_used_bytes).to eq(0)
64+
end
65+
66+
it 'returns 0 for memory_free_bytes' do
67+
expect(VCAP::Stats.memory_free_bytes).to eq(0)
68+
end
69+
70+
it 'returns 0 for cpu_load_average' do
71+
expect(VCAP::Stats.cpu_load_average).to eq(0)
72+
end
73+
end
1674
end

0 commit comments

Comments
 (0)