pimon 0.1.11 → 0.2.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 +7 -0
- data/bin/pimon +26 -19
- data/config/config.ru +11 -3
- data/config/default.yml +7 -13
- data/config/test.yml +6 -12
- data/config/test_broken.yml +0 -1
- data/lib/pimon.rb +2 -69
- data/lib/pimon/app.rb +81 -0
- data/lib/pimon/config.rb +34 -0
- data/lib/pimon/probe.rb +15 -0
- data/lib/pimon/probe/cpu_freq.rb +14 -0
- data/lib/pimon/probe/cpu_usage.rb +11 -8
- data/lib/pimon/probe/disk_usage.rb +11 -8
- data/lib/pimon/probe/memory_usage.rb +15 -10
- data/lib/pimon/probe/swap_usage.rb +16 -10
- data/lib/pimon/probe/system_memory.rb +16 -16
- data/lib/pimon/probe/temperature.rb +11 -13
- data/lib/pimon/probe/uptime.rb +37 -9
- data/lib/pimon/public/index.js +60 -120
- data/lib/pimon/public/normalize.css +427 -0
- data/lib/pimon/public/piecon.js +194 -0
- data/lib/pimon/public/style.css +13 -0
- data/lib/pimon/stats_collector.rb +66 -66
- data/lib/pimon/version.rb +1 -1
- data/lib/pimon/views/index.haml +17 -7
- data/pimon.gemspec +26 -25
- data/spec/{pimon_spec.rb → pimon/app_spec.rb} +9 -6
- data/spec/pimon/config_spec.rb +33 -0
- data/spec/pimon/stats_collector_spec.rb +13 -0
- data/spec/spec_helper.rb +9 -2
- metadata +195 -219
- data/.gitignore +0 -10
- data/.travis.yml +0 -6
- data/Gemfile +0 -20
- data/Gemfile.lock +0 -87
- data/README.md +0 -68
- data/Rakefile +0 -13
- data/WTFPL-LICENSE +0 -13
- data/bin/free.c +0 -12
- data/bin/makefile +0 -2
- data/bin/random.c +0 -21
- data/bin/random.h +0 -1
- data/bin/vmstat.c +0 -12
- data/lib/pimon/hash_extensions.rb +0 -12
- data/lib/pimon/pimon_config.rb +0 -32
- data/lib/pimon/probe/probe.rb +0 -13
- data/lib/pimon/probe/time_check.rb +0 -11
- data/lib/pimon/public/piecon.min.js +0 -5
- data/lib/pimon/stats.rb +0 -25
- data/spec/pimon_config_spec.rb +0 -17
- data/spec/stats_collector_spec.rb +0 -67
@@ -0,0 +1,194 @@
|
|
1
|
+
//
|
2
|
+
// piecon.js
|
3
|
+
//
|
4
|
+
// https://github.com/lipka/piecon
|
5
|
+
//
|
6
|
+
// Copyright (c) 2012 Lukas Lipka <lukaslipka@gmail.com>. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
(function(){
|
10
|
+
var Piecon = {};
|
11
|
+
|
12
|
+
var currentFavicon = null;
|
13
|
+
var originalFavicon = null;
|
14
|
+
var originalTitle = null;
|
15
|
+
var canvas = null;
|
16
|
+
var options = {};
|
17
|
+
var defaults = {
|
18
|
+
color: '#ff0084',
|
19
|
+
background: '#bbb',
|
20
|
+
shadow: '#fff',
|
21
|
+
fallback: false
|
22
|
+
};
|
23
|
+
|
24
|
+
var isRetina = window.devicePixelRatio > 1;
|
25
|
+
|
26
|
+
var ua = (function () {
|
27
|
+
var agent = navigator.userAgent.toLowerCase();
|
28
|
+
return function (browser) {
|
29
|
+
return agent.indexOf(browser) !== -1;
|
30
|
+
};
|
31
|
+
}());
|
32
|
+
|
33
|
+
var browser = {
|
34
|
+
ie: ua('msie'),
|
35
|
+
chrome: ua('chrome'),
|
36
|
+
webkit: ua('chrome') || ua('safari'),
|
37
|
+
safari: ua('safari') && !ua('chrome'),
|
38
|
+
mozilla: ua('mozilla') && !ua('chrome') && !ua('safari')
|
39
|
+
};
|
40
|
+
|
41
|
+
var getFaviconTag = function() {
|
42
|
+
var links = document.getElementsByTagName('link');
|
43
|
+
|
44
|
+
for (var i = 0, l = links.length; i < l; i++) {
|
45
|
+
if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') {
|
46
|
+
return links[i];
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
return false;
|
51
|
+
};
|
52
|
+
|
53
|
+
var removeFaviconTag = function() {
|
54
|
+
// Removed link element will not exist in Nodelist
|
55
|
+
var links = Array.prototype.slice.call(document.getElementsByTagName('link'));
|
56
|
+
var head = document.getElementsByTagName('head')[0];
|
57
|
+
|
58
|
+
for (var i = 0, l = links.length; i < l; i++) {
|
59
|
+
if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') {
|
60
|
+
head.removeChild(links[i]);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
var setFaviconTag = function(url) {
|
66
|
+
removeFaviconTag();
|
67
|
+
|
68
|
+
var link = document.createElement('link');
|
69
|
+
link.type = 'image/x-icon';
|
70
|
+
link.rel = 'icon';
|
71
|
+
link.href = url;
|
72
|
+
|
73
|
+
document.getElementsByTagName('head')[0].appendChild(link);
|
74
|
+
};
|
75
|
+
|
76
|
+
var getCanvas = function () {
|
77
|
+
if (!canvas) {
|
78
|
+
canvas = document.createElement("canvas");
|
79
|
+
if (isRetina) {
|
80
|
+
canvas.width = 32;
|
81
|
+
canvas.height = 32;
|
82
|
+
} else {
|
83
|
+
canvas.width = 16;
|
84
|
+
canvas.height = 16;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
return canvas;
|
89
|
+
};
|
90
|
+
|
91
|
+
var drawFavicon = function(percentage) {
|
92
|
+
var canvas = getCanvas();
|
93
|
+
var context = canvas.getContext("2d");
|
94
|
+
var percentage = percentage || 0;
|
95
|
+
var src = currentFavicon;
|
96
|
+
|
97
|
+
var faviconImage = new Image();
|
98
|
+
faviconImage.onload = function() {
|
99
|
+
if (context) {
|
100
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
101
|
+
|
102
|
+
// Draw shadow
|
103
|
+
context.beginPath();
|
104
|
+
context.moveTo(canvas.width / 2, canvas.height / 2);
|
105
|
+
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false);
|
106
|
+
context.fillStyle = options.shadow;
|
107
|
+
context.fill();
|
108
|
+
|
109
|
+
// Draw background
|
110
|
+
context.beginPath();
|
111
|
+
context.moveTo(canvas.width / 2, canvas.height / 2);
|
112
|
+
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false);
|
113
|
+
context.fillStyle = options.background;
|
114
|
+
context.fill();
|
115
|
+
|
116
|
+
// Draw pie
|
117
|
+
if (percentage > 0) {
|
118
|
+
context.beginPath();
|
119
|
+
context.moveTo(canvas.width / 2, canvas.height / 2);
|
120
|
+
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false);
|
121
|
+
context.lineTo(canvas.width / 2, canvas.height / 2);
|
122
|
+
context.fillStyle = options.color;
|
123
|
+
context.fill();
|
124
|
+
}
|
125
|
+
|
126
|
+
setFaviconTag(canvas.toDataURL());
|
127
|
+
}
|
128
|
+
};
|
129
|
+
|
130
|
+
// allow cross origin resource requests if the image is not a data:uri
|
131
|
+
// as detailed here: https://github.com/mrdoob/three.js/issues/1305
|
132
|
+
if (!src.match(/^data/)) {
|
133
|
+
faviconImage.crossOrigin = 'anonymous';
|
134
|
+
}
|
135
|
+
|
136
|
+
faviconImage.src = src;
|
137
|
+
};
|
138
|
+
|
139
|
+
var updateTitle = function(percentage) {
|
140
|
+
if (percentage > 0) {
|
141
|
+
document.title = '(' + percentage + '%) ' + originalTitle;
|
142
|
+
} else {
|
143
|
+
document.title = originalTitle;
|
144
|
+
}
|
145
|
+
};
|
146
|
+
|
147
|
+
Piecon.setOptions = function(custom) {
|
148
|
+
options = {};
|
149
|
+
|
150
|
+
for (var key in defaults){
|
151
|
+
options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key];
|
152
|
+
}
|
153
|
+
|
154
|
+
return this;
|
155
|
+
};
|
156
|
+
|
157
|
+
Piecon.setProgress = function(percentage) {
|
158
|
+
if (!originalTitle) {
|
159
|
+
originalTitle = document.title;
|
160
|
+
}
|
161
|
+
|
162
|
+
if (!originalFavicon || !currentFavicon) {
|
163
|
+
var tag = getFaviconTag();
|
164
|
+
originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico';
|
165
|
+
}
|
166
|
+
|
167
|
+
if (!isNaN(parseFloat(percentage)) && isFinite(percentage)) {
|
168
|
+
if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === true) {
|
169
|
+
// Fallback to updating the browser title if unsupported
|
170
|
+
return updateTitle(percentage);
|
171
|
+
} else if (options.fallback === 'force') {
|
172
|
+
updateTitle(percentage);
|
173
|
+
}
|
174
|
+
|
175
|
+
return drawFavicon(percentage);
|
176
|
+
}
|
177
|
+
|
178
|
+
return false;
|
179
|
+
};
|
180
|
+
|
181
|
+
Piecon.reset = function() {
|
182
|
+
if (originalTitle) {
|
183
|
+
document.title = originalTitle;
|
184
|
+
}
|
185
|
+
|
186
|
+
if (originalFavicon) {
|
187
|
+
currentFavicon = originalFavicon;
|
188
|
+
setFaviconTag(currentFavicon);
|
189
|
+
}
|
190
|
+
};
|
191
|
+
|
192
|
+
Piecon.setOptions(defaults);
|
193
|
+
window.Piecon = Piecon;
|
194
|
+
})();
|
@@ -1,75 +1,75 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'json'
|
3
|
-
require 'pimon/probe/cpu_usage'
|
4
|
-
require 'pimon/probe/disk_usage'
|
5
|
-
require 'pimon/probe/memory_usage'
|
6
|
-
require 'pimon/probe/swap_usage'
|
7
|
-
require 'pimon/probe/time_check'
|
8
|
-
require 'pimon/probe/temperature'
|
9
|
-
require 'pimon/probe/uptime'
|
10
|
-
require 'pimon/stats'
|
11
3
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
4
|
+
require 'pimon/probe'
|
5
|
+
|
6
|
+
module Pimon
|
7
|
+
class StatsCollector
|
8
|
+
attr_accessor :config
|
9
|
+
attr_accessor :last_update
|
10
|
+
attr_accessor :probes
|
11
|
+
attr_accessor :probe_threads
|
12
|
+
attr_reader :stats
|
13
|
+
|
14
|
+
CHART_PROBES = [
|
15
|
+
Pimon::Probe::CpuUsage,
|
16
|
+
Pimon::Probe::MemoryUsage,
|
17
|
+
Pimon::Probe::SwapUsage,
|
18
|
+
Pimon::Probe::DiskUsage,
|
19
|
+
Pimon::Probe::Temperature
|
23
20
|
]
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@
|
21
|
+
|
22
|
+
SINGLE_PROBES = [
|
23
|
+
Pimon::Probe::Uptime,
|
24
|
+
Pimon::Probe::CpuFreq
|
25
|
+
]
|
26
|
+
|
27
|
+
def initialize(config)
|
28
|
+
@config = config
|
29
|
+
@probes = {
|
30
|
+
charts: CHART_PROBES,
|
31
|
+
single: SINGLE_PROBES
|
32
|
+
}
|
33
|
+
@stats = { colors: config.colors, charts: {}, single: {}, hostname: config.hostname }
|
34
|
+
@probe_threads = []
|
35
|
+
@collection_mutex = Mutex.new
|
32
36
|
end
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
:uptime => uptime
|
49
|
-
}
|
50
|
-
|
51
|
-
@probes.each do |probe|
|
52
|
-
stats[probe.symbol] = {
|
53
|
-
:stats => @stats.range(probe.symbol),
|
54
|
-
:color => @config.chart[probe.symbol][:color],
|
55
|
-
:unit => probe.unit
|
56
|
-
} unless [:time, :uptime].include?(probe.symbol)
|
37
|
+
|
38
|
+
def collect_stats
|
39
|
+
@collection_mutex.synchronize do
|
40
|
+
self.last_update = Time.now
|
41
|
+
|
42
|
+
[:charts, :single].each do |stats_type|
|
43
|
+
probes[stats_type].each do |probe|
|
44
|
+
self.probe_threads = []
|
45
|
+
probe_threads << Thread.new do
|
46
|
+
sample = probe.check(last_update)
|
47
|
+
stats[stats_type][sample.probe_name] = sample
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
57
52
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
53
|
+
|
54
|
+
def show_stats
|
55
|
+
wait_for_stats_collection { stats }
|
56
|
+
end
|
57
|
+
|
58
|
+
def charts
|
59
|
+
wait_for_stats_collection { stats[:charts].keys }
|
60
|
+
end
|
61
|
+
|
62
|
+
def single_stats
|
63
|
+
wait_for_stats_collection { stats[:single].keys }
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def wait_for_stats_collection
|
69
|
+
@collection_mutex.synchronize do
|
70
|
+
probe_threads.each(&:join)
|
71
|
+
yield if block_given?
|
72
|
+
end
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
data/lib/pimon/version.rb
CHANGED
data/lib/pimon/views/index.haml
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
%html
|
2
2
|
%header
|
3
3
|
%title Pimon
|
4
|
-
|
5
|
-
%
|
6
|
-
%
|
4
|
+
-#%link{ :href => '/favicon.ico', :rel => :icon, :type => :"image/x-icon" }
|
5
|
+
%link{ :href => '/normalize.css', :rel => :stylesheet, :type => :"text/css" }
|
6
|
+
%link{ :href => '/style.css', :rel => :stylesheet, :type => :"text/css" }
|
7
|
+
%script{ :src => 'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery-1.8.0.min.js' }
|
8
|
+
%script{ :src => '/piecon.js' }
|
9
|
+
%script{ :src => 'https://cdnjs.cloudflare.com/ajax/libs/smoothie/1.27.0/smoothie.min.js' }
|
7
10
|
%script{ :src => '/index.js' }
|
11
|
+
|
8
12
|
%body
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
%h1.hostname= hostname
|
14
|
+
- single_stats.each do |stat_name|
|
15
|
+
.single_stat{ :id => stat_name }
|
16
|
+
%strong= "#{stat_name.upcase}: "
|
17
|
+
%span.stat
|
18
|
+
|
19
|
+
- charts.each do |chart_name|
|
20
|
+
.chart
|
21
|
+
%h2= chart_name.upcase
|
22
|
+
%canvas{ :id => "#{chart_name}_chart" }
|
data/pimon.gemspec
CHANGED
@@ -1,35 +1,36 @@
|
|
1
|
-
|
2
|
-
$: << File.expand_path('./lib')
|
3
|
-
require 'pimon/version'
|
1
|
+
require_relative 'lib/pimon/version'
|
4
2
|
|
5
3
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
7
|
-
s.version = Pimon::VERSION
|
4
|
+
s.name = 'pimon'
|
5
|
+
s.version = Pimon::VERSION
|
6
|
+
s.licenses = ['WTFPL']
|
8
7
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = [
|
10
|
-
s.email = [
|
8
|
+
s.authors = ['Pedro Carriço']
|
9
|
+
s.email = ['pedro.carrico@gmail.com']
|
11
10
|
s.homepage = 'http://pimon.pedrocarrico.net/'
|
12
11
|
s.summary = 'Pimon - Raspberry Pi server monitor'
|
13
12
|
s.description = 'Pimon is a simple server monitor designed for the Raspberry Pi.'
|
14
13
|
s.post_install_message = 'Thank you for using Pimon :-)'
|
15
|
-
|
14
|
+
|
16
15
|
s.required_ruby_version = '>= 1.9'
|
17
|
-
|
18
|
-
s.files =
|
19
|
-
s.test_files =
|
20
|
-
s.executables =
|
16
|
+
|
17
|
+
s.files = Dir.glob('{lib,config}/**/*') << 'pimon.gemspec'
|
18
|
+
s.test_files = Dir.glob('{test,spec,features}/**/*')
|
19
|
+
s.executables = 'pimon'
|
21
20
|
s.require_paths = ['lib']
|
22
|
-
|
23
|
-
s.add_runtime_dependency
|
24
|
-
s.add_runtime_dependency
|
25
|
-
s.add_runtime_dependency
|
26
|
-
s.add_runtime_dependency
|
27
|
-
s.add_runtime_dependency
|
28
|
-
|
29
|
-
|
30
|
-
s.add_development_dependency '
|
31
|
-
s.add_development_dependency '
|
32
|
-
s.add_development_dependency 'simplecov',
|
33
|
-
s.add_development_dependency 'simplecov-rcov',
|
34
|
-
s.add_development_dependency 'timecop',
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'haml', '= 4.0.7'
|
23
|
+
s.add_runtime_dependency 'sinatra', '= 1.4.6'
|
24
|
+
s.add_runtime_dependency 'faye-websocket', '= 0.10.0'
|
25
|
+
s.add_runtime_dependency 'sys-uptime', '= 0.6.2'
|
26
|
+
s.add_runtime_dependency 'thin', '= 1.6.3'
|
27
|
+
|
28
|
+
s.add_development_dependency 'rack-test', '= 0.6.2'
|
29
|
+
s.add_development_dependency 'rspec', '= 3.0.0'
|
30
|
+
s.add_development_dependency 'rubocop', '=0.33.0'
|
31
|
+
s.add_development_dependency 'simplecov', '= 0.10.0'
|
32
|
+
s.add_development_dependency 'simplecov-rcov', '= 0.2.3'
|
33
|
+
s.add_development_dependency 'timecop', '= 0.7.1'
|
34
|
+
s.add_development_dependency 'coveralls', '= 0.8.2'
|
35
|
+
s.add_development_dependency 'pry', '= 0.10.0'
|
35
36
|
end
|