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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +22 -1
- data/app/authorization.rb +27 -0
- data/app/models/application_model.rb +15 -0
- data/app/models/bandwidth.rb +15 -16
- data/app/models/cpu_load.rb +17 -12
- data/app/models/cpu_usage.rb +7 -5
- data/app/models/disk_io.rb +15 -16
- data/app/models/filesystem_usage.rb +7 -5
- data/app/models/memory_usage.rb +7 -5
- data/app/puny_monitor.rb +22 -17
- data/app/scheduler.rb +2 -3
- data/app/views/index.erb +33 -17
- data/app/views/layout.erb +10 -7
- data/config/environment.rb +0 -1
- data/lib/puny_monitor/version.rb +1 -1
- data/lib/system_utils.rb +19 -19
- data/public/javascript/Chart.bundle.js +24003 -0
- data/public/javascript/chartkick.js +2570 -0
- data/public/javascript/index.js +2 -4
- data/public/style.css +14 -0
- metadata +11 -16
- data/.ruby-version +0 -1
- data/Rakefile +0 -50
- data/config.ru +0 -5
- data/db/migrate/20231023000000_add_indices_to_created_at_columns.rb +0 -12
- data/db/schema.rb +0 -61
- data/db/seeds.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b39f83645fed8b173fe448a4c9f93dfc886e15a0c368b0137e315caa001bf414
|
4
|
+
data.tar.gz: 19f2757bb81d07c6d132dc9570e4f4724ad5f69ad8ca06f930a302db6f47ec43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d76d92559a392db462a141e0350535cbb3dbf3052a17983ca54cb85c7c54d2e980c4d555194616aa0cf6d6031b7091e43d999db171d67f5e2157f1ae1b5886c
|
7
|
+
data.tar.gz: 8017307c65f35ca42c653bfb9a3231af8df5334134b558c1935b9ac8ff34faeee8b2ad7f7c1d116934e2fa5f3ab3b02923d5883c29bad20892095c02cac6a844
|
data/CHANGELOG.md
ADDED
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`.
|
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
|
data/app/models/bandwidth.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class Bandwidth <
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
{
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
data/app/models/cpu_load.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class CpuLoad <
|
4
|
-
def self.average_load(start_time,
|
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
|
-
{
|
7
|
-
{
|
8
|
-
{
|
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
|
data/app/models/cpu_usage.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class CpuUsage <
|
4
|
-
def self.average_usage(start_time,
|
3
|
+
class CpuUsage < ApplicationModel
|
4
|
+
def self.average_usage(start_time, minutes)
|
5
5
|
where(created_at: start_time..)
|
6
|
-
.
|
7
|
-
.
|
8
|
-
|
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/models/disk_io.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class DiskIO <
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
{
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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 <
|
4
|
-
def self.average_usage(start_time,
|
3
|
+
class FilesystemUsage < ApplicationModel
|
4
|
+
def self.average_usage(start_time, minutes)
|
5
5
|
where(created_at: start_time..)
|
6
|
-
.
|
7
|
-
.
|
8
|
-
|
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/models/memory_usage.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class MemoryUsage <
|
4
|
-
def self.average_usage(start_time,
|
3
|
+
class MemoryUsage < ApplicationModel
|
4
|
+
def self.average_usage(start_time, minutes)
|
5
5
|
where(created_at: start_time..)
|
6
|
-
.
|
7
|
-
.
|
8
|
-
|
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("
|
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: {
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
4
|
-
|
5
|
-
<
|
6
|
-
value="
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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"
|
data/config/environment.rb
CHANGED
data/lib/puny_monitor/version.rb
CHANGED
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
|
-
|
16
|
+
prev_cpu[:irq] + prev_cpu[:softirq] + prev_cpu[:steal]
|
17
17
|
non_idle = current_cpu[:user] + current_cpu[:nice] + current_cpu[:system] +
|
18
|
-
|
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
|
-
|
33
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
.lines
|
115
|
+
.drop(2)
|
116
|
+
.first
|
117
|
+
.split
|
118
|
+
.last
|
119
119
|
|
120
120
|
stats = File.read("#{proc_path}/diskstats")
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
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,
|