kstats-node 1.0.0 → 1.0.1

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.
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: