puny-monitor 0.1.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef7da3ad71ee116621cfd11bc930e6ab5624aad481afaa024e6e09790916cde4
4
- data.tar.gz: d590745c16a3ca947e1a1af8b91931cbf9daec21e9f1703a308b8be7e92e5bf5
3
+ metadata.gz: b39f83645fed8b173fe448a4c9f93dfc886e15a0c368b0137e315caa001bf414
4
+ data.tar.gz: 19f2757bb81d07c6d132dc9570e4f4724ad5f69ad8ca06f930a302db6f47ec43
5
5
  SHA512:
6
- metadata.gz: 345ed87c689aa7c153009f8a3f21fa33778ed97cf1db0a3e60948717ee0906886c4d9eb037a6b4602567354a34c89378f9fa57fb7b1f4a3596024f1580f2b687
7
- data.tar.gz: af40c578d0c669f4216e0eaaa456154835819934c79f6befb40ea9200e888eba3854bef9594278644718ab242bc0c9804c862f8bdbca02d1df323ebeae6892e3
6
+ metadata.gz: 5d76d92559a392db462a141e0350535cbb3dbf3052a17983ca54cb85c7c54d2e980c4d555194616aa0cf6d6031b7091e43d999db171d67f5e2157f1ae1b5886c
7
+ data.tar.gz: 8017307c65f35ca42c653bfb9a3231af8df5334134b558c1935b9ac8ff34faeee8b2ad7f7c1d116934e2fa5f3ab3b02923d5883c29bad20892095c02cac6a844
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.2.0] - 2025-08-18
4
+
5
+ - Add HTTP authentication
6
+ - Upgrade to Ruby 3.4
7
+
8
+ ## [0.1.0] - 2024-09-15
9
+
10
+ - Initial release
data/README.md CHANGED
@@ -33,6 +33,20 @@ docker run --rm \
33
33
 
34
34
  Visit [localhost:4567](http://localhost:4567) to check your system data. To see how to deploy Puny Monitor in a production environment see [Deployment].
35
35
 
36
+ ## Authentication
37
+
38
+ Puny monitor supports Basic HTTP Authentication. To enable authentication set both the `PUNY_USERNAME` and `PUNY_PASSWORD` environment variables. For example, using with `docker run`:
39
+
40
+ ```
41
+ docker run --rm \
42
+ -v=/:/host:ro,rslave -v=puny-data:/puny-monitor/db \
43
+ -e HOST_PATH=/host \
44
+ -e PUNY_USERNAME=admin \
45
+ -e PUNY_PASSWORD=secret \
46
+ -p 4567:4567 \
47
+ hschne/puny-monitor:latest
48
+ ```
49
+
36
50
  ## Deployment
37
51
 
38
52
  Puny Monitor was made with [Kamal](https://kamal-deploy.org/) and [Ruby on Rails](https://rubyonrails.org/) in mind. It is recommended that you deploy it as an accessory to your application. Add the following lines to `config/deploy.yml`:
@@ -81,7 +95,14 @@ To put it simply, Puny Monitor replicates [Digital Ocean's Monitoring](https://w
81
95
 
82
96
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
83
97
 
84
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
98
+ To install this gem onto your local machine, run `bundle exec rake install`. To run Puny Monitor locally use
99
+ ```
100
+ bundle exec rackup
101
+ ```
102
+
103
+ Alternatively, you may use the various docker helpers defined in the [Rakefile].
104
+
105
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
85
106
 
86
107
  ## Contributing
87
108
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PunyMonitor
4
+ module Authorization
5
+ def self.included(base)
6
+ return unless authorize?
7
+
8
+ base.use Rack::Auth::Basic, "Puny Monitor" do |username, password|
9
+ username == self.username && password == self.password
10
+ end
11
+ end
12
+
13
+ def self.username
14
+ @username ||= ENV.fetch("PUNY_USERNAME", nil)
15
+ end
16
+
17
+ def self.password
18
+ @password ||= ENV.fetch("PUNY_PASSWORD", nil)
19
+ end
20
+
21
+ def self.authorize?
22
+ puts username
23
+ puts password
24
+ username && password
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationModel < ActiveRecord::Base
4
+ self.abstract_class = true
5
+
6
+ scope :group_by_time, ->(minutes) {
7
+ interval_seconds = minutes * 60
8
+ group("strftime('%s', created_at) / #{interval_seconds} * #{interval_seconds}")
9
+ }
10
+
11
+ def self.group_format(minutes)
12
+ interval_seconds = minutes * 60
13
+ "strftime('%s', created_at) / #{interval_seconds} * #{interval_seconds}"
14
+ end
15
+ end
@@ -1,21 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Bandwidth < ActiveRecord::Base
4
- class << self
5
- def average_usage(start_time, group_by)
6
- [
7
- { name: "Incoming Mbps", data: average_for_period(:incoming_mbps, start_time, group_by) },
8
- { name: "Outgoing Mbps", data: average_for_period(:outgoing_mbps, start_time, group_by) }
9
- ]
10
- end
3
+ class Bandwidth < ApplicationModel
4
+ def self.average_usage(start_time, minutes)
5
+ data = where(created_at: start_time..)
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(incoming_mbps), 2) as avg_incoming"),
10
+ Arel.sql("ROUND(AVG(outgoing_mbps), 2) as avg_outgoing")
11
+ )
11
12
 
12
- private
13
-
14
- def average_for_period(column, start_time, group_by)
15
- where(created_at: start_time..)
16
- .group_by_period(group_by, :created_at)
17
- .average(column)
18
- .transform_values { |value| value&.round(2) }
19
- end
13
+ incoming = data.to_h { |period, incoming, _| [period, incoming] }
14
+ outgoing = data.to_h { |period, _, outgoing| [period, outgoing] }
15
+ [
16
+ {name: "Incoming Mbps", data: incoming},
17
+ {name: "Outgoing Mbps", data: outgoing}
18
+ ]
20
19
  end
21
20
  end
@@ -1,18 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CpuLoad < ActiveRecord::Base
4
- def self.average_load(start_time, end_time, group_by)
3
+ class CpuLoad < ApplicationModel
4
+ def self.average_load(start_time, minutes)
5
+ data = where(created_at: start_time..)
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(one_minute), 2) as avg_one"),
10
+ Arel.sql("ROUND(AVG(five_minutes), 2) as avg_five"),
11
+ Arel.sql("ROUND(AVG(fifteen_minutes), 2) as avg_fifteen")
12
+ )
13
+
14
+ one = data.to_h { |period, one, _, _| [period, one] }
15
+ five = data.to_h { |period, _, five, _| [period, five] }
16
+ fifteen = data.to_h { |period, _, _, fifteen| [period, fifteen] }
5
17
  [
6
- { name: "1 minute", data: average_for_period(:one_minute, start_time, end_time, group_by) },
7
- { name: "5 minutes", data: average_for_period(:five_minutes, start_time, end_time, group_by) },
8
- { name: "15 minutes", data: average_for_period(:fifteen_minutes, start_time, end_time, group_by) }
18
+ {name: "1 minute", data: one},
19
+ {name: "5 minutes", data: five},
20
+ {name: "15 minutes", data: fifteen}
9
21
  ]
10
22
  end
11
-
12
- def self.average_for_period(column, start_time, end_time, group_by)
13
- where(created_at: start_time..end_time)
14
- .group_by_period(group_by, :created_at)
15
- .average(column)
16
- .transform_values { |value| value&.round(2) }
17
- end
18
23
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CpuUsage < ActiveRecord::Base
4
- def self.average_usage(start_time, group_by)
3
+ class CpuUsage < ApplicationModel
4
+ def self.average_usage(start_time, minutes)
5
5
  where(created_at: start_time..)
6
- .group_by_period(group_by, :created_at, expand_range: true)
7
- .average(:used_percent)
8
- .transform_values { |value| value&.round(2) }
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(used_percent), 2) as avg_usage")
10
+ )
9
11
  end
10
12
  end
@@ -1,21 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class DiskIO < ActiveRecord::Base
4
- class << self
5
- def average_io(start_time, group_by)
6
- [
7
- { name: "Read MB/s", data: average_for_period(:read_mb_per_sec, start_time, group_by) },
8
- { name: "Write MB/s", data: average_for_period(:write_mb_per_sec, start_time, group_by) }
9
- ]
10
- end
3
+ class DiskIO < ApplicationModel
4
+ def self.average_io(start_time, minutes)
5
+ data = where(created_at: start_time..)
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(read_mb_per_sec), 2) as avg_read"),
10
+ Arel.sql("ROUND(AVG(write_mb_per_sec), 2) as avg_write")
11
+ )
11
12
 
12
- private
13
-
14
- def average_for_period(column, start_time, group_by)
15
- where(created_at: start_time..)
16
- .group_by_period(group_by, :created_at)
17
- .average(column)
18
- .transform_values { |value| value&.round(2) }
19
- end
13
+ read = data.to_h { |period, read, _| [period, read] }
14
+ write = data.to_h { |period, _, write| [period, write] }
15
+ [
16
+ {name: "Read MB/s", data: read},
17
+ {name: "Write MB/s", data: write}
18
+ ]
20
19
  end
21
20
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class FilesystemUsage < ActiveRecord::Base
4
- def self.average_usage(start_time, group_by)
3
+ class FilesystemUsage < ApplicationModel
4
+ def self.average_usage(start_time, minutes)
5
5
  where(created_at: start_time..)
6
- .group_by_period(group_by, :created_at)
7
- .average(:used_percent)
8
- .transform_values { |value| value&.round(2) }
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(used_percent), 2) as avg_usage")
10
+ )
9
11
  end
10
12
  end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class MemoryUsage < ActiveRecord::Base
4
- def self.average_usage(start_time, group_by)
3
+ class MemoryUsage < ApplicationModel
4
+ def self.average_usage(start_time, minutes)
5
5
  where(created_at: start_time..)
6
- .group_by_period(group_by, :created_at)
7
- .average(:used_percent)
8
- .transform_values { |value| value&.round(2) }
6
+ .group_by_time(minutes)
7
+ .pluck(
8
+ Arel.sql("datetime(#{group_format(minutes)}, 'unixepoch') as period"),
9
+ Arel.sql("ROUND(AVG(used_percent), 2) as avg_usage")
10
+ )
9
11
  end
10
12
  end
data/app/puny_monitor.rb CHANGED
@@ -2,14 +2,17 @@
2
2
 
3
3
  require "rufus-scheduler"
4
4
  require_relative "scheduler"
5
+ require_relative "authorization"
5
6
  require_relative "../lib/system_utils"
6
7
 
7
8
  module PunyMonitor
8
9
  class App < Sinatra::Base
10
+ # include Authorization
11
+
9
12
  configure do
10
13
  register Sinatra::ActiveRecordExtension
11
14
  @scheduler = Rufus::Scheduler.new
12
- @scheduler.every("5s") { Scheduler.collect_data }
15
+ @scheduler.every("10s") { Scheduler.collect_data }
13
16
  @scheduler.every("1h") { Scheduler.cleanup_old_data }
14
17
  end
15
18
 
@@ -22,7 +25,7 @@ module PunyMonitor
22
25
  set :database_file, "../config/database.yml"
23
26
 
24
27
  get "/" do
25
- erb :index, locals: { params:, logo: }
28
+ erb :index, locals: {params:, logo:}
26
29
  end
27
30
 
28
31
  get "/up" do
@@ -31,32 +34,32 @@ module PunyMonitor
31
34
 
32
35
  get "/data/cpu_usage" do
33
36
  content_type :json
34
- CpuUsage.average_usage(start_time, group_by).to_json
37
+ CpuUsage.average_usage(start_time, interval).to_json
35
38
  end
36
39
 
37
40
  get "/data/cpu_load" do
38
41
  content_type :json
39
- CpuLoad.average_load(start_time, Time.now, group_by).to_json
42
+ CpuLoad.average_load(start_time, interval).to_json
40
43
  end
41
44
 
42
45
  get "/data/memory_usage" do
43
46
  content_type :json
44
- MemoryUsage.average_usage(start_time, group_by).to_json
47
+ MemoryUsage.average_usage(start_time, interval).to_json
45
48
  end
46
49
 
47
50
  get "/data/filesystem_usage" do
48
51
  content_type :json
49
- FilesystemUsage.average_usage(start_time, group_by).to_json
52
+ FilesystemUsage.average_usage(start_time, interval).to_json
50
53
  end
51
54
 
52
55
  get "/data/disk_io" do
53
56
  content_type :json
54
- DiskIO.average_io(start_time, group_by).to_json
57
+ DiskIO.average_io(start_time, interval).to_json
55
58
  end
56
59
 
57
60
  get "/data/bandwidth" do
58
61
  content_type :json
59
- Bandwidth.average_usage(start_time, group_by).to_json
62
+ Bandwidth.average_usage(start_time, interval).to_json
60
63
  end
61
64
 
62
65
  private
@@ -68,11 +71,8 @@ module PunyMonitor
68
71
  end
69
72
  end
70
73
 
71
- def duration
72
- params[:duration] || "1d"
73
- end
74
-
75
74
  def start_time
75
+ duration = params[:duration] || "1d"
76
76
  case duration
77
77
  when "1h" then 1.hour.ago
78
78
  when "3d" then 3.days.ago
@@ -82,11 +82,16 @@ module PunyMonitor
82
82
  end
83
83
  end
84
84
 
85
- def group_by
86
- case duration
87
- when "1h", "1d" then :minute
88
- else :hour
89
- end
85
+ def interval
86
+ (params[:interval] || "15").to_i
87
+ end
88
+
89
+ def chart_url(endpoint)
90
+ query_params = []
91
+ query_params << "duration=#{params[:duration]}" if params[:duration]
92
+ query_params << "interval=#{params[:interval]}" if params[:interval]
93
+ query_string = query_params.empty? ? "" : "?#{query_params.join("&")}"
94
+ "#{endpoint}#{query_string}"
90
95
  end
91
96
  end
92
97
  end
data/app/scheduler.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../lib/system_utils"
4
- require "debug"
5
4
 
6
5
  module PunyMonitor
7
6
  class Scheduler
@@ -10,8 +9,8 @@ module PunyMonitor
10
9
  CpuUsage.create(used_percent: SystemUtils.cpu_usage_percent)
11
10
  cpu_load_averages = SystemUtils.cpu_load_average
12
11
  CpuLoad.create(one_minute: cpu_load_averages[0],
13
- five_minutes: cpu_load_averages[1],
14
- fifteen_minutes: cpu_load_averages[2])
12
+ five_minutes: cpu_load_averages[1],
13
+ fifteen_minutes: cpu_load_averages[2])
15
14
  MemoryUsage.create(used_percent: SystemUtils.memory_usage_percent)
16
15
  FilesystemUsage.create(used_percent: SystemUtils.filesystem_usage_percent)
17
16
 
data/app/views/index.erb CHANGED
@@ -1,15 +1,31 @@
1
1
  <section class="controls">
2
- <form action="/" method="get">
3
- <select name="duration" onchange="this.form.submit()">
4
- <option value="1h" <%= params[:duration] == '1h' ? 'selected' : '' %>>1 Hour</option>
5
- <option
6
- value="1d"
7
- <%= params[:duration] == '1d' || params[:duration].nil? ? 'selected' : '' %>
8
- >1 Day</option>
9
- <option value="3d" <%= params[:duration] == '3d' ? 'selected' : '' %>>3 Days</option>
10
- <option value="1w" <%= params[:duration] == '1w' ? 'selected' : '' %>>1 Week</option>
11
- <option value="1m" <%= params[:duration] == '1m' ? 'selected' : '' %>>1 Month</option>
12
- </select>
2
+ <form class="controls__form" action="/" method="get">
3
+
4
+ <label for="duration">Duration
5
+ <select id="duration" name="duration" onchange="this.form.submit()">
6
+ <option value="1h" <%= params[:duration] == '1h' ? 'selected' : '' %>>1 Hour</option>
7
+ <option
8
+ value="1d"
9
+ <%= params[:duration] == '1d' || params[:duration].nil? ? 'selected' : '' %>
10
+ >1 Day</option>
11
+ <option value="3d" <%= params[:duration] == '3d' ? 'selected' : '' %>>3 Days</option>
12
+ <option value="1w" <%= params[:duration] == '1w' ? 'selected' : '' %>>1 Week</option>
13
+ <option value="1m" <%= params[:duration] == '1m' ? 'selected' : '' %>>1 Month</option>
14
+ </select>
15
+ </label>
16
+
17
+ <label for="interval">Aggregation Interval
18
+ <select id="interval" name="interval" onchange="this.form.submit()">
19
+ <option value="5" <%= params[:interval] == '5' ? 'selected' : '' %>>5 minutes</option>
20
+ <option
21
+ value="15"
22
+ <%= params[:interval] == '15' || params[:interval].nil? ? 'selected' : '' %>
23
+ >15 minutes</option>
24
+ <option value="60" <%= params[:interval] == '60' ? 'selected' : '' %>>1 hour</option>
25
+ <option value="120" <%= params[:interval] == '120' ? 'selected' : '' %>>2 hours</option>
26
+ <option value="1440" <%= params[:interval] == '1440' ? 'selected' : '' %>>1 day</option>
27
+ </select>
28
+ </label>
13
29
  </form>
14
30
  </section>
15
31
 
@@ -17,7 +33,7 @@
17
33
 
18
34
  <div class="tile">
19
35
  <h2>CPU Usage</h2>
20
- <%= area_chart "/data/cpu_usage?duration=#{params[:duration] || "1d"}",
36
+ <%= area_chart chart_url("/data/cpu_usage"),
21
37
  ytitle: "CPU Usage (%)",
22
38
  min: 0,
23
39
  max: 100,
@@ -31,7 +47,7 @@
31
47
 
32
48
  <div class="tile">
33
49
  <h2>CPU Load</h2>
34
- <%= line_chart "/data/cpu_load?duration=#{params[:duration] || "1d"}",
50
+ <%= line_chart chart_url("/data/cpu_load"),
35
51
  ytitle: "Load Average",
36
52
  library: {
37
53
  title: {
@@ -43,7 +59,7 @@
43
59
 
44
60
  <div class="tile">
45
61
  <h2>Memory Usage</h2>
46
- <%= area_chart "/data/memory_usage?duration=#{params[:duration] || "1d"}",
62
+ <%= area_chart chart_url("/data/memory_usage"),
47
63
  ytitle: "Memory Usage (%)",
48
64
  min: 0,
49
65
  max: 100,
@@ -57,7 +73,7 @@
57
73
 
58
74
  <div class="tile">
59
75
  <h2>Filesystem Usage</h2>
60
- <%= area_chart "/data/filesystem_usage?duration=#{params[:duration] || "1d"}",
76
+ <%= area_chart chart_url("/data/filesystem_usage"),
61
77
  ytitle: "Used Space (%)",
62
78
  min: 0,
63
79
  max: 100,
@@ -71,7 +87,7 @@
71
87
 
72
88
  <div class="tile">
73
89
  <h2>Disk I/O</h2>
74
- <%= area_chart "/data/disk_io?duration=#{params[:duration] || "1d"}",
90
+ <%= area_chart chart_url("/data/disk_io"),
75
91
  ytitle: "MB/s",
76
92
  library: {
77
93
  title: {
@@ -83,7 +99,7 @@
83
99
 
84
100
  <div class="tile">
85
101
  <h2>Bandwidth</h2>
86
- <%= area_chart "/data/bandwidth?duration=#{params[:duration] || "1d"}",
102
+ <%= area_chart chart_url("/data/bandwidth"),
87
103
  ytitle: "Bandwidth (Mbps)",
88
104
  library: {
89
105
  title: {
data/app/views/layout.erb CHANGED
@@ -13,13 +13,16 @@
13
13
  <link rel="icon" href="favicon.ico" sizes="32x32">
14
14
  <link rel="icon" href="icon.svg" type="image/svg+xml">
15
15
 
16
- <script
17
- src="https://cdn.jsdelivr.net/npm/chartkick@4.2.0/dist/chartkick.min.js"
18
- ></script>
19
- <script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
20
- <script
21
- src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@2.0.0/dist/chartjs-adapter-date-fns.bundle.min.js"
22
- ></script>
16
+ <script type="importmap">
17
+ {
18
+ "imports": {
19
+ "chartkick": "./javascript/chartkick.js",
20
+ "Chart.bundle": "./javascript/Chart.bundle.js"
21
+ }
22
+ }
23
+ </script>
24
+ <script type="module" src="javascript/index.js"></script>
25
+
23
26
  <link
24
27
  rel="preload"
25
28
  href="fonts/Rubik.woff2"
@@ -8,7 +8,6 @@ Bundler.require(:default, ENV.fetch("RACK_ENV", nil))
8
8
  require "sinatra/contrib"
9
9
  require "sinatra/activerecord"
10
10
  require "rufus-scheduler"
11
- require "groupdate"
12
11
  require "chartkick"
13
12
  require "sqlite3"
14
13
  require "sys-filesystem"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PunyMonitor
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/system_utils.rb CHANGED
@@ -13,9 +13,9 @@ class SystemUtils
13
13
  idle = current_cpu[:idle] + current_cpu[:iowait]
14
14
 
15
15
  prev_non_idle = prev_cpu[:user] + prev_cpu[:nice] + prev_cpu[:system] +
16
- prev_cpu[:irq] + prev_cpu[:softirq] + prev_cpu[:steal]
16
+ prev_cpu[:irq] + prev_cpu[:softirq] + prev_cpu[:steal]
17
17
  non_idle = current_cpu[:user] + current_cpu[:nice] + current_cpu[:system] +
18
- current_cpu[:irq] + current_cpu[:softirq] + current_cpu[:steal]
18
+ current_cpu[:irq] + current_cpu[:softirq] + current_cpu[:steal]
19
19
 
20
20
  prev_total = prev_idle + prev_non_idle
21
21
  total = idle + non_idle
@@ -29,8 +29,8 @@ class SystemUtils
29
29
 
30
30
  def cpu_load_average
31
31
  File.read("#{proc_path}/loadavg").split.take(3)
32
- .map(&:to_f)
33
- .map { |value| value.round(2) }
32
+ .map(&:to_f)
33
+ .map { |value| value.round(2) }
34
34
  end
35
35
 
36
36
  def memory_usage_percent
@@ -111,16 +111,16 @@ class SystemUtils
111
111
 
112
112
  def read_disk_stats
113
113
  primary_disk = File.read("#{proc_path}/partitions")
114
- .lines
115
- .drop(2)
116
- .first
117
- .split
118
- .last
114
+ .lines
115
+ .drop(2)
116
+ .first
117
+ .split
118
+ .last
119
119
 
120
120
  stats = File.read("#{proc_path}/diskstats")
121
- .lines
122
- .map(&:split)
123
- .find { |line| line[2] == primary_disk }
121
+ .lines
122
+ .map(&:split)
123
+ .find { |line| line[2] == primary_disk }
124
124
 
125
125
  {
126
126
  read_sectors: stats[5].to_i,
@@ -130,14 +130,14 @@ class SystemUtils
130
130
 
131
131
  def read_network_stats
132
132
  primary_interface = File.read("#{proc_path}/net/route")
133
- .lines
134
- .drop(1)
135
- .find { |line| line.split[1] == "00000000" }
136
- &.split&.first
133
+ .lines
134
+ .drop(1)
135
+ .find { |line| line.split[1] == "00000000" }
136
+ &.split&.first
137
137
  stats = File.read("#{proc_path}/net/dev")
138
- .lines
139
- .map(&:split)
140
- .find { |line| line[0].chomp(":") == primary_interface }
138
+ .lines
139
+ .map(&:split)
140
+ .find { |line| line[0].chomp(":") == primary_interface }
141
141
 
142
142
  {
143
143
  rx_bytes: stats[1].to_i,