pimon 0.1.11 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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