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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/bin/pimon +26 -19
  3. data/config/config.ru +11 -3
  4. data/config/default.yml +7 -13
  5. data/config/test.yml +6 -12
  6. data/config/test_broken.yml +0 -1
  7. data/lib/pimon.rb +2 -69
  8. data/lib/pimon/app.rb +81 -0
  9. data/lib/pimon/config.rb +34 -0
  10. data/lib/pimon/probe.rb +15 -0
  11. data/lib/pimon/probe/cpu_freq.rb +14 -0
  12. data/lib/pimon/probe/cpu_usage.rb +11 -8
  13. data/lib/pimon/probe/disk_usage.rb +11 -8
  14. data/lib/pimon/probe/memory_usage.rb +15 -10
  15. data/lib/pimon/probe/swap_usage.rb +16 -10
  16. data/lib/pimon/probe/system_memory.rb +16 -16
  17. data/lib/pimon/probe/temperature.rb +11 -13
  18. data/lib/pimon/probe/uptime.rb +37 -9
  19. data/lib/pimon/public/index.js +60 -120
  20. data/lib/pimon/public/normalize.css +427 -0
  21. data/lib/pimon/public/piecon.js +194 -0
  22. data/lib/pimon/public/style.css +13 -0
  23. data/lib/pimon/stats_collector.rb +66 -66
  24. data/lib/pimon/version.rb +1 -1
  25. data/lib/pimon/views/index.haml +17 -7
  26. data/pimon.gemspec +26 -25
  27. data/spec/{pimon_spec.rb → pimon/app_spec.rb} +9 -6
  28. data/spec/pimon/config_spec.rb +33 -0
  29. data/spec/pimon/stats_collector_spec.rb +13 -0
  30. data/spec/spec_helper.rb +9 -2
  31. metadata +195 -219
  32. data/.gitignore +0 -10
  33. data/.travis.yml +0 -6
  34. data/Gemfile +0 -20
  35. data/Gemfile.lock +0 -87
  36. data/README.md +0 -68
  37. data/Rakefile +0 -13
  38. data/WTFPL-LICENSE +0 -13
  39. data/bin/free.c +0 -12
  40. data/bin/makefile +0 -2
  41. data/bin/random.c +0 -21
  42. data/bin/random.h +0 -1
  43. data/bin/vmstat.c +0 -12
  44. data/lib/pimon/hash_extensions.rb +0 -12
  45. data/lib/pimon/pimon_config.rb +0 -32
  46. data/lib/pimon/probe/probe.rb +0 -13
  47. data/lib/pimon/probe/time_check.rb +0 -11
  48. data/lib/pimon/public/piecon.min.js +0 -5
  49. data/lib/pimon/stats.rb +0 -25
  50. data/spec/pimon_config_spec.rb +0 -17
  51. data/spec/stats_collector_spec.rb +0 -67
data/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- .idea
2
- .rspec
3
- bin/free
4
- bin/vmstat
5
- bin/*.o
6
- config/thin/development_config.yml
7
- coverage
8
- log
9
- pids
10
- sandbox.sh
@@ -1,6 +0,0 @@
1
- rvm:
2
- - 1.9.3
3
- script: "rake spec"
4
- notifications:
5
- email:
6
- - pedro.carrico@gmail.com
data/Gemfile DELETED
@@ -1,20 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'rake', '~> 10.1.0'
4
- gem 'haml', '~> 4.0.3'
5
- gem 'sinatra', '~> 1.4.3', :require => 'sinatra/base'
6
- gem 'em-websocket', '= 0.3.8'
7
- gem 'sinatra-websocket', '~> 0.2.1'
8
- gem 'sys-uptime', '~> 0.6.1'
9
- gem 'thin', '~> 1.5.1'
10
-
11
- gem 'pry', '~> 0.9.12.2' , :group => [:development, :test]
12
-
13
- group :test do
14
- gem 'rack-test', '~> 0.6.2'
15
- gem 'rspec', '~> 2.14.1'
16
- gem 'simplecov', '~> 0.7.1', :require => false
17
- gem 'simplecov-rcov', '~> 0.2.3'
18
- gem 'timecop', '~> 0.6.1'
19
- gem 'coveralls', '~> 0.6.7', require: false
20
- end
@@ -1,87 +0,0 @@
1
- GEM
2
- remote: https://rubygems.org/
3
- specs:
4
- addressable (2.3.3)
5
- coderay (1.0.9)
6
- colorize (0.5.8)
7
- coveralls (0.6.7)
8
- colorize
9
- multi_json (~> 1.3)
10
- rest-client
11
- simplecov (>= 0.7)
12
- thor
13
- daemons (1.1.9)
14
- diff-lcs (1.2.4)
15
- em-websocket (0.3.8)
16
- addressable (>= 2.1.1)
17
- eventmachine (>= 0.12.9)
18
- eventmachine (1.0.3)
19
- ffi (1.4.0)
20
- haml (4.0.3)
21
- tilt
22
- method_source (0.8.1)
23
- mime-types (1.23)
24
- multi_json (1.6.1)
25
- pry (0.9.12.2)
26
- coderay (~> 1.0.5)
27
- method_source (~> 0.8)
28
- slop (~> 3.4)
29
- rack (1.5.2)
30
- rack-protection (1.5.0)
31
- rack
32
- rack-test (0.6.2)
33
- rack (>= 1.0)
34
- rake (10.1.0)
35
- rest-client (1.6.7)
36
- mime-types (>= 1.16)
37
- rspec (2.14.1)
38
- rspec-core (~> 2.14.0)
39
- rspec-expectations (~> 2.14.0)
40
- rspec-mocks (~> 2.14.0)
41
- rspec-core (2.14.4)
42
- rspec-expectations (2.14.0)
43
- diff-lcs (>= 1.1.3, < 2.0)
44
- rspec-mocks (2.14.1)
45
- simplecov (0.7.1)
46
- multi_json (~> 1.0)
47
- simplecov-html (~> 0.7.1)
48
- simplecov-html (0.7.1)
49
- simplecov-rcov (0.2.3)
50
- simplecov (>= 0.4.1)
51
- sinatra (1.4.3)
52
- rack (~> 1.4)
53
- rack-protection (~> 1.4)
54
- tilt (~> 1.3, >= 1.3.4)
55
- sinatra-websocket (0.2.1)
56
- em-websocket (~> 0.3.6)
57
- eventmachine
58
- thin (>= 1.3.1)
59
- slop (3.4.5)
60
- sys-uptime (0.6.1)
61
- ffi (>= 1.0.0)
62
- thin (1.5.1)
63
- daemons (>= 1.0.9)
64
- eventmachine (>= 0.12.6)
65
- rack (>= 1.0.0)
66
- thor (0.18.1)
67
- tilt (1.4.1)
68
- timecop (0.6.1)
69
-
70
- PLATFORMS
71
- ruby
72
-
73
- DEPENDENCIES
74
- coveralls (~> 0.6.7)
75
- em-websocket (= 0.3.8)
76
- haml (~> 4.0.3)
77
- pry (~> 0.9.12.2)
78
- rack-test (~> 0.6.2)
79
- rake (~> 10.1.0)
80
- rspec (~> 2.14.1)
81
- simplecov (~> 0.7.1)
82
- simplecov-rcov (~> 0.2.3)
83
- sinatra (~> 1.4.3)
84
- sinatra-websocket (~> 0.2.1)
85
- sys-uptime (~> 0.6.1)
86
- thin (~> 1.5.1)
87
- timecop (~> 0.6.1)
data/README.md DELETED
@@ -1,68 +0,0 @@
1
- # Pimon
2
-
3
- [![Build Status](https://secure.travis-ci.org/pedrocarrico/pimon.png)](http://travis-ci.org/pedrocarrico/pimon) [![Dependency Status](https://gemnasium.com/pedrocarrico/pimon.png?travis)](https://gemnasium.com/pedrocarrico/pimon) [![Gem Version](https://badge.fury.io/rb/pimon.png)](http://badge.fury.io/rb/pimon) [![Code Climate](https://codeclimate.com/github/pedrocarrico/pimon.png)](https://codeclimate.com/github/pedrocarrico/pimon) [![Coverage Status](https://coveralls.io/repos/pedrocarrico/pimon/badge.png?branch=master)](https://coveralls.io/r/pedrocarrico/pimon)
4
-
5
- ![Pimon](http://pedrocarrico.net/pimon.jpg "Pimon")
6
-
7
- ## Description
8
- Pimon is a simple server monitor designed for the Raspberry Pi.
9
-
10
- ## What do I need to get it to work?
11
- 1. Clone this repo: git clone git://github.com/pedrocarrico/pimon.git
12
- 2. bundle
13
- 3. bin/pimon start # run the sinatra app
14
- 4. go to http://localhost:3000 and PROFIT!
15
- Optionally you may install it as a gem and run it, please check "Installing as a gem" further down.
16
-
17
- ## Configuration
18
- Configuration is done through a YAML file, you may check some examples on the config directory.
19
-
20
- 1. chart - colors for each chart
21
- 2. hostname - optional hostname to show on the chart subtitle, defaults to `hostname` if not set
22
- 3. stats_collector - configure number of stats and time period between them
23
-
24
- ## Installing as a gem
25
- ```
26
- gem install pimon
27
- ```
28
- After installation just do _pimon start_ and go to http://localhost:3000 and check your stats.
29
- If you want you may run Pimon with other options:
30
- ```
31
- Usage: pimon start|stop [options]
32
- Options:
33
- -c, --config CONFIG YAML configuration file for pimon
34
- -d, --daemonize Run Pimon daemonized in the background
35
- -e, --environment ENVIRONMENT Application environment (default: "development", options: "development", "production")
36
- -i, --interface INTERFACE Hostname or IP address of the interface to listen on (default: "localhost")
37
- -p, --port PORT Port to use (default: 3000)
38
- -P, --pid PIDFILE File to store PID (default: /tmp/pimon.pid)
39
- ```
40
- (This will only work on your Raspberry Pi and perhaps some other linux distros, check the quirks section for more info).
41
-
42
- ## Running tests
43
- To run the coverage suite:
44
- ```
45
- rake coverage:spec
46
- ```
47
- Results will be in coverage/index.html directory.
48
-
49
- ## Quirks
50
- Pimon uses _vmstat_ and _free_ to collect it's stats from the operating system and these are only
51
- available on operating systems that have the /proc filesystem.
52
- So if you want to develop on a Mac you may use the mock implementations that are in the bin directory.
53
- The mock implementations are programmed in C and mimic the output of _vmstat_ and _free_.
54
- They just change and generate some random values on the observed stats using /dev/urandom.
55
- To use them you must first compile them using _make_ and then include the bin directory of this project
56
- in your $PATH to have them available when you run the sinatra application.
57
- The temperature stat is only available with the latest Raspbian distro (2012-09-18) on your Raspberry Pi and will (may)
58
- not work if you're developing on other systems.
59
- Pimon only works with Ruby 1.9+, please refer to [my blog](http://blog.pedrocarrico.net/post/29478085586/compiling-and-installing-ruby-on-the-raspberry-pi-using "Compiling and installing ruby on the raspberry pi using rbenv…") for a way to install Ruby 1.9.3 on your Raspberry Pi.
60
-
61
- ## TODO
62
- 1. Improve disk stats, have a way of having custom mount points
63
- 2. Change configuration in realtime
64
- 3. Cpu frequency probe
65
- 4. Persist stats
66
-
67
- ## Copyright
68
- Licensed under the [WTFPL](http://en.wikipedia.org/wiki/WTFPL "Do What The Fuck You Want To Public License") license.
data/Rakefile DELETED
@@ -1,13 +0,0 @@
1
- require 'rspec/core/rake_task'
2
-
3
- desc 'run specs'
4
- RSpec::Core::RakeTask.new
5
-
6
- namespace :coverage do
7
- desc 'run rspec code coverage'
8
- task :spec do
9
- ENV['COVERAGE'] = 'on'
10
- FileUtils.rm_r 'coverage', :force => true
11
- Rake::Task[:spec].execute
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
- Version 2, December 2004
3
-
4
- Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
-
6
- Everyone is permitted to copy and distribute verbatim or modified
7
- copies of this license document, and changing it is allowed as long
8
- as the name is changed.
9
-
10
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
-
13
- 0. You just DO WHAT THE FUCK YOU WANT TO.
data/bin/free.c DELETED
@@ -1,12 +0,0 @@
1
- #include <stdio.h>
2
- #include <stdlib.h>
3
-
4
- int main (int argc, char *argv[])
5
- {
6
- int mem_used = generate_random();
7
- int swap_used = generate_random();
8
-
9
- printf(" total used free shared buffers cached\nMem: 215 %d %d 0 4 110\nSwap: 100 %d %d\n", mem_used, 215 - mem_used, swap_used, 100 - swap_used);
10
-
11
- exit (0);
12
- }
@@ -1,2 +0,0 @@
1
- all:
2
- gcc -c random.c vmstat.c free.c; gcc -o vmstat vmstat.o random.o ;gcc -o free free.o random.o
@@ -1,21 +0,0 @@
1
- #include <stdio.h>
2
- #include <unistd.h>
3
- #include <stdlib.h>
4
- #include <math.h>
5
-
6
- int generate_random()
7
- {
8
- FILE *urandom;
9
- unsigned int seed;
10
- int cpu_idle;
11
-
12
- urandom = fopen ("/dev/urandom", "r");
13
- if (urandom == NULL) {
14
- fprintf (stderr, "ERROR: Cannot open /dev/urandom!\n");
15
- exit (1);
16
- }
17
- fread (&seed, sizeof (seed), 1, urandom);
18
- srand (seed);
19
-
20
- return ((int) floor (rand() * 100.0 / ((double) RAND_MAX + 1) ) + 1);
21
- }
@@ -1 +0,0 @@
1
- extern int generate_random();
@@ -1,12 +0,0 @@
1
- #include <stdio.h>
2
- #include <stdlib.h>
3
- #include "random.h"
4
-
5
- int main (int argc, char *argv[])
6
- {
7
- int cpu_idle = generate_random();
8
-
9
- printf("procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----\n r b swpd free buff cache si so bi bo in cs us sy id wa\n 1 0 10976 50992 4900 113188 1 2 109 244 101 183 11 10 77 1\n 0 0 10976 50992 4900 113188 0 0 0 0 8366 315 10 5 %d 0\n", cpu_idle);
10
-
11
- exit (0);
12
- }
@@ -1,12 +0,0 @@
1
- # As seen in https://gist.github.com/151324
2
- module HashExtensions
3
- def symbolize_keys
4
- inject({}) do |acc, (k,v)|
5
- key = String === k ? k.to_sym : k
6
- value = Hash === v ? v.symbolize_keys : v
7
- acc[key] = value
8
- acc
9
- end
10
- end
11
- end
12
- Hash.send(:include, HashExtensions)
@@ -1,32 +0,0 @@
1
- require 'pimon/hash_extensions'
2
- require 'yaml'
3
-
4
- class PimonConfig
5
- def self.create_new(filename)
6
- return self.new(filename)
7
- end
8
-
9
- def chart
10
- @config[:chart]
11
- end
12
-
13
- def stats
14
- @config[:stats_collector]
15
- end
16
-
17
- def hostname
18
- @hostname ||= @config[:hostname].nil? ? `hostname` : @config[:hostname]
19
- end
20
-
21
- private
22
-
23
- def initialize(filename)
24
- begin
25
- @config = YAML.load_file(filename).symbolize_keys
26
- @config.freeze
27
- rescue Exception => e
28
- puts "Error while loading config file: #{filename}"
29
- raise e
30
- end
31
- end
32
- end
@@ -1,13 +0,0 @@
1
- class Probe
2
- def self.check
3
- raise "Not implemented"
4
- end
5
-
6
- def self.symbol
7
- raise "Not implemented"
8
- end
9
-
10
- def self.unit
11
- '%'
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- require 'pimon/probe/probe'
2
-
3
- class Probe::TimeCheck < Probe
4
- def self.check
5
- Time.now.strftime("%Y-%m-%d %H:%M:%S")
6
- end
7
-
8
- def self.symbol
9
- :time
10
- end
11
- end
@@ -1,5 +0,0 @@
1
- (function(){var i={},j=null,k=null,f=null,g=null,h={},l={color:"#ff0084",background:"#bbb",shadow:"#fff",fallback:!1},c,o=navigator.userAgent.toLowerCase();c=function(e){return-1!==o.indexOf(e)};var p=c("msie");c("chrome");c("chrome")||c("safari");var q=c("safari")&&!c("chrome");c("mozilla")&&!c("chrome")&&c("safari");var m=function(e){for(var a=document.getElementsByTagName("link"),c=document.getElementsByTagName("head")[0],f=0,h=a.length;f<h;f++)("icon"===a[f].getAttribute("rel")||"shortcut icon"===
2
- a[f].getAttribute("rel"))&&c.removeChild(a[f]);a=document.createElement("link");a.type="image/x-icon";a.rel="icon";a.href=e;document.getElementsByTagName("head")[0].appendChild(a)},n=function(){g||(g=document.createElement("canvas"),g.width=16,g.height=16);return g};i.setOptions=function(e){h={};for(var a in l)h[a]=e.hasOwnProperty(a)?e[a]:l[a];return this};i.setProgress=function(e){f||(f=document.title);if(!k||!j){var a;a:{a=document.getElementsByTagName("link");for(var c=0,i=a.length;c<i;c++)if("icon"===
3
- a[c].getAttribute("rel")||"shortcut icon"===a[c].getAttribute("rel")){a=a[c];break a}a=!1}k=j=a?a.getAttribute("href"):"/favicon.ico"}if(!isNaN(parseFloat(e))&&isFinite(e))if(!n().getContext||p||q||!0==h.fallback)document.title=0<e?"("+e+"%) "+f:f;else{"force"===h.fallback&&(document.title=0<e?"("+e+"%) "+f:f);var g=e,b=n(),d=b.getContext("2d"),g=g||0,e=j;a=new Image;a.onload=function(){if(d){d.clearRect(0,0,16,16);d.beginPath();d.moveTo(b.width/2,b.height/2);d.arc(b.width/2,b.height/2,Math.min(b.width/
4
- 2,b.height/2),0,Math.PI*2,false);d.fillStyle=h.shadow;d.fill();d.beginPath();d.moveTo(b.width/2,b.height/2);d.arc(b.width/2,b.height/2,Math.min(b.width/2,b.height/2)-2,0,Math.PI*2,false);d.fillStyle=h.background;d.fill();if(g>0){d.beginPath();d.moveTo(b.width/2,b.height/2);d.arc(b.width/2,b.height/2,Math.min(b.width/2,b.height/2)-2,-0.5*Math.PI,(-0.5+2*g/100)*Math.PI,false);d.lineTo(b.width/2,b.height/2);d.fillStyle=h.color;d.fill()}m(b.toDataURL())}};e.match(/^data/)||(a.crossOrigin="anonymous");
5
- a.src=e}else return!1};i.reset=function(){f&&(document.title=f);k&&(j=k,m(j))};i.setOptions(l);window.Piecon=i})();
@@ -1,25 +0,0 @@
1
- class Stats
2
-
3
- def initialize(queues)
4
- @stats = {}
5
- queues.each do |queue|
6
- @stats[queue] = []
7
- end
8
- end
9
-
10
- def index(queue, index)
11
- @stats[queue][index]
12
- end
13
-
14
- def push(queue, value)
15
- @stats[queue].push(value)
16
- end
17
-
18
- def shift(queue)
19
- @stats[queue].shift
20
- end
21
-
22
- def range(queue)
23
- @stats[queue]
24
- end
25
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'PimonConfig' do
4
- context 'when created for the test environment' do
5
- subject { PimonConfig.create_new("#{File.dirname(__FILE__)}/../config/test.yml") }
6
-
7
- its(:chart) { should == { :cpu => { :color => '#D2691E' }, :disk => { :color => '#CDC673' }, :mem => { :color => '#87CEFA' }, :temp => {:color=>"#FF9B04"}, :swap => { :color => '#3CB371' } } }
8
- its(:stats) { should == { :number_of_stats => 6, :time_period_in_min => 10 } }
9
- its(:hostname) { should == 'test_hostname' }
10
- end
11
-
12
- context 'when created with an invalid environment' do
13
- it 'should raise an error' do
14
- expect{ PimonConfig.create_new('invalid') }.to raise_error(Errno::ENOENT)
15
- end
16
- end
17
- end
@@ -1,67 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require 'spec_helper'
4
- require 'json'
5
-
6
- describe 'StatsCollector' do
7
- context 'when new with a valid config' do
8
- before do
9
- @stats_collector = StatsCollector.new(PimonConfig.create_new("#{File.dirname(__FILE__)}/../config/test.yml"))
10
- end
11
- subject { @stats_collector }
12
-
13
- it 'should collect_stats' do
14
- Probe::CpuUsage.should_receive(:check)
15
- Probe::DiskUsage.should_receive(:check)
16
- Probe::MemoryUsage.should_receive(:check)
17
- Probe::SwapUsage.should_receive(:check)
18
- Probe::Temperature.should_receive(:check)
19
- Probe::Uptime.should_receive(:check)
20
-
21
- @stats_collector.collect_stats
22
- end
23
-
24
- its(:show_stats) {
25
- should == {
26
- :time => { :stats => [] },
27
- :hostname => 'test_hostname',
28
- :uptime => [],
29
- :cpu => { :stats => [], :color => '#D2691E', :unit => '%' },
30
- :mem => { :stats => [], :color => '#87CEFA', :unit => '%' },
31
- :swap => {:stats => [], :color => '#3CB371', :unit => '%' },
32
- :disk => {:stats => [], :color => '#CDC673', :unit => '%' },
33
- :temp => {:stats => [], :color => '#FF9B04', :unit => 'ºC' }
34
- }.to_json
35
- }
36
-
37
- context 'when collected some stats' do
38
- before do
39
- Timecop.freeze(Time.local(2012, 9, 1, 12, 0, 0))
40
-
41
- Probe::CpuUsage.should_receive(:check).any_number_of_times.and_return(50)
42
- Probe::DiskUsage.should_receive(:check).any_number_of_times.and_return(25)
43
- Probe::MemoryUsage.should_receive(:check).any_number_of_times.and_return(78)
44
- Probe::SwapUsage.should_receive(:check).any_number_of_times.and_return(50)
45
- Probe::Temperature.should_receive(:check).any_number_of_times.and_return(40)
46
- Probe::Uptime.should_receive(:check).any_number_of_times.and_return([1,2,3,4])
47
-
48
- 7.times do
49
- @stats_collector.collect_stats
50
- end
51
- end
52
-
53
- its(:show_stats) {
54
- should == {
55
- :time => { :stats => ['12:00:00', '12:00:00', '12:00:00', '12:00:00', '12:00:00', '12:00:00']},
56
- :hostname => 'test_hostname',
57
- :uptime => [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]],
58
- :cpu => {:stats => [50, 50, 50, 50, 50, 50], :color => '#D2691E', :unit => '%'},
59
- :mem => { :stats => [78, 78, 78, 78, 78, 78], :color =>'#87CEFA', :unit => '%'},
60
- :swap=>{ :stats => [50, 50, 50, 50, 50, 50], :color => '#3CB371', :unit => '%'},
61
- :disk=>{ :stats => [25, 25, 25, 25, 25, 25], :color => '#CDC673', :unit => '%'},
62
- :temp=>{ :stats => [40, 40, 40, 40, 40, 40], :color => '#FF9B04', :unit => 'ºC'}
63
- }.to_json
64
- }
65
- end
66
- end
67
- end