kstats-node 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+ test/db
data/bin/kstats-node ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+
6
+ class Time
7
+ def to_db
8
+ strftime "%Y%m%d%H%M%S"
9
+ end
10
+ end
11
+
12
+ require 'optparse'
13
+ require 'yaml'
14
+ require 'kstats/node'
15
+ require 'json'
16
+
17
+ options = {}
18
+ optparse = OptionParser.new do |opts|
19
+ opts.banner = "Usage: kstats-node [options]"
20
+
21
+ opts.on('-h', '--help', 'Show help screen'){ puts opts; exit }
22
+
23
+ opts.on('-c', '--config CONF', 'Set configuration file') do |config|
24
+ options[:config] = config
25
+ end
26
+ end
27
+
28
+ optparse.parse!
29
+ require 'sinatra'
30
+
31
+ #Parse the configuration file:
32
+ config = YAML::load(File.read(options[:config]))
33
+ Kstats::Node::CONFIG.merge!(config)
34
+
35
+ Kstats::Node::Database.init
36
+
37
+ get '/probes/list' do
38
+ Kstats::Node::Probe.list.to_json
39
+ end
40
+
41
+ #Display data for daily infos
42
+ get '/probe/:id/:target' do
43
+ now = Time.now
44
+
45
+ case params[:target]
46
+ when 'tick'
47
+ start = now - (60*60*24)
48
+ when 'weekly'
49
+ start = now - 7*(60*60*24)
50
+ when 'monthly'
51
+ start = now - 30*(60*60*24)
52
+ when 'yearly'
53
+ start = now - 365*(60*60*24)
54
+ else
55
+ return 403
56
+ end
57
+
58
+
59
+ data =Kstats::Node::Database.db.execute(
60
+ "SELECT probe_key, date, probe_value FROM probe_data WHERE period_type=? AND probe_id = ? AND date >= ? ORDER BY date ASC",
61
+ params[:target],
62
+ params[:id],
63
+ start.to_s
64
+ )
65
+
66
+ datas = {}
67
+ data.each do |record|
68
+ key, date, value = record
69
+ datas[key] ||= []
70
+ datas[key] << [Time.parse(date), value]
71
+ end
72
+
73
+ datas.each do |key, value|
74
+ datas[key] = Kstats::Node::Helper.generate_array(value, start, (now-start)/60, 288)
75
+ end
76
+
77
+ {
78
+ start_at: start,
79
+ format: Kstats::Node::Probe.get_format(params[:id]),
80
+ data: datas
81
+ }.to_json
82
+ end
83
+
84
+ Kstats::Node::Worker.launch!
data/kstats-node.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = %q{Provide a simple way to make probe on system values, and monitorign theses values.}
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
+ spec.executables << 'kstats-node'
15
16
 
16
17
  spec.files = `git ls-files -z`.split("\x0")
17
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -0,0 +1,5 @@
1
+ module Kstats
2
+ module Node
3
+ CONFIG={}
4
+ end
5
+ end
@@ -0,0 +1,43 @@
1
+ require 'sqlite3'
2
+
3
+ module Kstats
4
+ module Node
5
+ module Database
6
+ class << self
7
+ attr_reader :db
8
+
9
+ def init
10
+ @db = SQLite3::Database.new( Kstats::Node::CONFIG['db_dir'] )
11
+ @db.execute [
12
+ "CREATE TABLE IF NOT EXISTS probe_data (id INTEGER PRIMARY KEY ASC, date DATETIME, period_type STRING, probe_id STRING, probe_key STRING, probe_value NUMBER)",
13
+ "CREATE INDEX IF NOT EXISTS probe_data_period_type ON probe_data(period_type)",
14
+ "CREATE INDEX IF NOT EXISTS probe_data_date ON probe_data(date)",
15
+ "CREATE INDEX IF NOT EXISTS probe_data_probe_id ON probe_data(probe_id)",
16
+ "CREATE INDEX IF NOT EXISTS probe_data_probe_key ON probe_data(probe_key)"
17
+ ].join(";")
18
+ end
19
+
20
+ def execute query
21
+ @db.execute(query)
22
+ end
23
+
24
+ def save_probes_data probes, type
25
+ time = Time.now
26
+
27
+ probes.each do |name, values|
28
+ @db.close
29
+ @db = SQLite3::Database.new( Kstats::Node::CONFIG['db_dir'] )
30
+
31
+ sql = <<SQL
32
+ INSERT INTO probe_data (date, period_type, probe_id, probe_key, probe_value)
33
+ VALUES (?, ?, ?, ?, ?)
34
+ SQL
35
+ values.each do |probe_key, probe_value|
36
+ @db.execute(sql, time.to_s, type.to_s, name.to_s, probe_key.to_s, probe_value)
37
+ end
38
+ end
39
+ end
40
+ end #<< self
41
+ end #Class
42
+ end #Node
43
+ end #Kstats
@@ -0,0 +1,42 @@
1
+ module Kstats
2
+ module Node
3
+ module Helper
4
+ #Entry:
5
+ # Data from probe with:
6
+ # 0: Date of the pick
7
+ # 1: Value of the pick
8
+ # Output:
9
+ # An array with value of average of each points
10
+ def self.generate_array data, start, period, nb_points
11
+ out_array = Array.new nb_points
12
+
13
+ for i in 0...nb_points
14
+ out_array[i] = [0.0, 0.0] # value and coef.
15
+ end
16
+
17
+ data.each do |x|
18
+ #Position of the data over the period:
19
+ poz = (x[0] - start)/60 # In minutes
20
+ poz = poz / period.to_f # In percent between [0..1]
21
+
22
+ next if poz < 0.0 || poz > 1.0
23
+
24
+ p1,p2,f = (poz * nb_points).floor, (poz*nb_points).ceil, (poz*nb_points).abs.modulo(1)
25
+
26
+ if f>0.5
27
+ output = out_array[p1]
28
+ else
29
+ output = out_array[p2]
30
+ end
31
+
32
+ unless output.nil?
33
+ output[0] = (x[1] + output[1]*output[0]) / ( output[1] + 1)
34
+ output[1] += 1
35
+ end
36
+ end
37
+
38
+ out_array.map{ |x| x[0].round(3) }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,165 @@
1
+ module Kstats
2
+ module Node
3
+ class Probe
4
+
5
+ class << self
6
+ attr_accessor :registered
7
+
8
+ def register name, &block
9
+ @registered << Probe.new(name).from_dsl(&block)
10
+ end
11
+
12
+ def get_format probe
13
+ probe = @fixed_registered.select{|x| x.id == probe }.first
14
+ if probe.nil?
15
+ return nil
16
+ else
17
+ {
18
+ type: probe.type,
19
+ variables: probe.variables.inject({}){ |h, x|
20
+ h[x.name] = {}
21
+ h[x.name][:desc] = x.desc
22
+ h[x.name][:color] = x.color
23
+ h
24
+ }
25
+ }
26
+ end
27
+ end
28
+
29
+ def reload_and_test!
30
+ @fixed_registered = @registered
31
+ @registered = []
32
+
33
+ dir = Kstats::Node::CONFIG['probes_dir']
34
+
35
+ Dir[File.join(dir, "*.rb")].each do |probe_file|
36
+ begin
37
+ load(probe_file)
38
+ rescue => e
39
+ puts "Unable to load #{probe_file}: #{e}"
40
+ puts "*\t#{e.backtrace.join("\n*\t")}"
41
+ end
42
+ end
43
+
44
+ probes = {}
45
+
46
+ @registered.each do |probe|
47
+ begin
48
+ probes[probe.id] = probe.test
49
+ rescue => e
50
+ puts "Exception for probe #{probe.id} : #{e.message}"
51
+ puts "*\t#{e.backtrace.join("\n*\t")}"
52
+ end
53
+ end
54
+
55
+ @fixed_registered = @registered
56
+
57
+ probes
58
+ end
59
+
60
+ def list
61
+ probe_categories = {}
62
+ @fixed_registered.each do |probe|
63
+ probe_categories[probe.category] ||= []
64
+ probe_categories[probe.category] << { name: probe.name, id: probe.id }
65
+ end
66
+
67
+ probe_categories
68
+ end
69
+ end
70
+
71
+ class Variable
72
+ attr_reader :name
73
+ attr_accessor :desc, :color, :probe
74
+
75
+ def initialize name, parent
76
+ @name = name
77
+ @parent = parent
78
+ end
79
+
80
+ def command
81
+ @parent.command
82
+ end
83
+
84
+ def test
85
+ instance_eval(&probe)
86
+ end
87
+
88
+ def from_dsl &block
89
+ dsl = DSL.new(self)
90
+ dsl.instance_eval(&block)
91
+
92
+ return self
93
+ end
94
+
95
+ class DSL
96
+ def initialize variable
97
+ @variable = variable
98
+ end
99
+
100
+ def desc val
101
+ @variable.desc = val
102
+ end
103
+
104
+ def color val
105
+ @variable.color = val
106
+ end
107
+
108
+ def probe &val
109
+ @variable.probe = val
110
+ end
111
+ end
112
+ end
113
+
114
+ attr_reader :id
115
+ attr_accessor :variables, :category, :name, :type, :command, :command_block
116
+
117
+ def initialize id
118
+ @variables = []
119
+ @id = id
120
+ end
121
+
122
+ def from_dsl &block
123
+ DSL.new(self).instance_eval(&block)
124
+
125
+ return self
126
+ end
127
+
128
+ def add_variable var
129
+ @variables << var
130
+ end
131
+
132
+ def test
133
+ @command = self.command_block.call unless self.command_block.nil?
134
+
135
+ @variables.inject({}){|h, x| h[x.name] = x.test; h }
136
+ end
137
+
138
+ class DSL
139
+ def initialize probe
140
+ @probe = probe
141
+ end
142
+
143
+ def category val
144
+ @probe.category = val
145
+ end
146
+
147
+ def name val
148
+ @probe.name = val
149
+ end
150
+
151
+ def command &block
152
+ @probe.command_block = block
153
+ end
154
+
155
+ def type val
156
+ @probe.type = val
157
+ end
158
+
159
+ def variable name, &block
160
+ @probe.add_variable Variable.new(name, @probe).from_dsl(&block)
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -1,5 +1,5 @@
1
1
  module Kstats
2
2
  module Node
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
@@ -0,0 +1,46 @@
1
+ module Kstats
2
+ module Node
3
+ class Worker
4
+ def self.launch!
5
+ insert_month = 0
6
+ insert_week = 0
7
+ insert_year = 0
8
+
9
+ thread = Thread.new do
10
+ begin
11
+ begin
12
+ puts "New probe tick."
13
+ probes = Kstats::Node::Probe.reload_and_test!
14
+
15
+ if insert_month == 0
16
+ insert_month = 30
17
+ Database.save_probes_data(probes, :monthly)
18
+ end
19
+
20
+ if insert_week == 0
21
+ insert_week = 7
22
+ Database.save_probes_data(probes, :weekly)
23
+ end
24
+
25
+ if insert_year == 0
26
+ insert_year = 365
27
+ Database.save_probes_data(probes, :yearly)
28
+ end
29
+
30
+ insert_month -= 1
31
+ insert_week -= 1
32
+ insert_year -= 1
33
+
34
+ Database.save_probes_data(probes, :tick)
35
+ rescue Exception => e
36
+ puts e.message
37
+ puts e.backtrace
38
+ end
39
+ sleep(300)
40
+ end while true
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
data/test/conf.yml ADDED
@@ -0,0 +1,2 @@
1
+ probes_dir: test/probes
2
+ db_dir: test/db/test.sqlite3
@@ -0,0 +1,32 @@
1
+ Kstats::Node::Probe.register 'cpu' do
2
+ category 'Hardware'
3
+ name 'CPU usage'
4
+
5
+ type :curve
6
+
7
+ command{ `cat /proc/loadavg`.split(/\s/).map(&:to_f) }
8
+
9
+ variable :load_avg_1mn do
10
+ desc 'Load average (1mn)'
11
+ color '#0000FF'
12
+ probe do
13
+ command[0]
14
+ end
15
+ end
16
+
17
+ variable :load_avg_5mn do
18
+ desc 'Load average (5mn)'
19
+ color '#00FF00'
20
+ probe do
21
+ command[1]
22
+ end
23
+ end
24
+
25
+ variable :load_avg_15mn do
26
+ desc 'Load average (15mn)'
27
+ color '#FF0000'
28
+ probe do
29
+ command[2]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ Kstats::Node::Probe.register 'disk' do
2
+ category 'Hardware'
3
+ name 'Disk usage'
4
+
5
+ type :curve
6
+
7
+ _self = self
8
+ instance_eval do
9
+ def parsedf
10
+ disks = `df`.split(/\n/).map do |x|
11
+ x.split(/\s+/)
12
+ end
13
+
14
+ disks.reject!{|x| x[0] == 'udev' || x[0] == 'none' || x[0] == 'tmpfs' || x[0] == 'Filesystem' }
15
+ disks.map!{|x| {name: x[0], space: 100*(x[2].to_f/x[1].to_f) }}
16
+ end
17
+ end
18
+
19
+ parsedf.each do |infos|
20
+ var = infos[:name]
21
+
22
+ variable var do
23
+ desc "Filling of `#{infos[:name]}`"
24
+ color "#0000FF"
25
+ probe do
26
+ val = _self.parsedf.select{|x| x[:name] == var }.first[:space]
27
+
28
+ puts val
29
+
30
+ val
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,37 @@
1
+ Kstats::Node::Probe.register 'hwmem' do
2
+ category 'Hardware'
3
+ name 'Memory usage'
4
+
5
+ type :curve
6
+
7
+ command do
8
+ cmd = `cat /proc/meminfo`
9
+ lines = cmd.split(/\n/)
10
+
11
+ memtotal = lines.select{|x| x =~ /MemTotal/ }.first.gsub(/[^0-9]/, '').to_f
12
+ active = lines.select{|x| x =~ /Active/ }.first.gsub(/[^0-9]/, '').to_f
13
+ inactive = lines.select{|x| x =~ /Inactive/ }.first.gsub(/[^0-9]/, '').to_f
14
+ memfree = lines.select{|x| x =~ /MemFree/ }.first.gsub(/[^0-9]/, '').to_f
15
+ swaptotal = lines.select{|x| x =~ /SwapTotal/ }.first.gsub(/[^0-9]/, '').to_f
16
+ swapfree = lines.select{|x| x =~ /SwapFree/ }.first.gsub(/[^0-9]/, '').to_f
17
+
18
+ [memtotal, active, inactive, memfree, swaptotal, swapfree]
19
+ end
20
+
21
+ variable :mem_load do
22
+ desc 'Memory load (%)'
23
+ color '#0000FF'
24
+ probe do
25
+ 1-(command[3]/command[0])
26
+ end
27
+ end
28
+
29
+ variable :swap_load do
30
+ desc 'Swap load (%)'
31
+ color '#FF0000'
32
+
33
+ probe do
34
+ 1-(command[5]/command[4])
35
+ end
36
+ end
37
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kstats-node
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -79,7 +79,8 @@ description: Provide a simple way to make probe on system values, and monitorign
79
79
  values.
80
80
  email:
81
81
  - yacine@kosmogo.com
82
- executables: []
82
+ executables:
83
+ - kstats-node
83
84
  extensions: []
84
85
  extra_rdoc_files: []
85
86
  files:
@@ -88,9 +89,19 @@ files:
88
89
  - LICENSE.txt
89
90
  - README.md
90
91
  - Rakefile
92
+ - bin/kstats-node
91
93
  - kstats-node.gemspec
92
94
  - lib/kstats/node.rb
95
+ - lib/kstats/node/config.rb
96
+ - lib/kstats/node/database.rb
97
+ - lib/kstats/node/helper.rb
98
+ - lib/kstats/node/probe.rb
93
99
  - lib/kstats/node/version.rb
100
+ - lib/kstats/node/worker.rb
101
+ - test/conf.yml
102
+ - test/probes/cpu.rb
103
+ - test/probes/disk.rb
104
+ - test/probes/memory.rb
94
105
  homepage: ''
95
106
  licenses:
96
107
  - MIT
@@ -116,5 +127,9 @@ rubygems_version: 1.8.28
116
127
  signing_key:
117
128
  specification_version: 3
118
129
  summary: Node for the project kstats
119
- test_files: []
130
+ test_files:
131
+ - test/conf.yml
132
+ - test/probes/cpu.rb
133
+ - test/probes/disk.rb
134
+ - test/probes/memory.rb
120
135
  has_rdoc: