prrd 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4c074fd1d609522279be5d2493075487a4b43403
4
+ data.tar.gz: 96b588b278c0f30d663ba3d8766b6e843d87936d
5
+ SHA512:
6
+ metadata.gz: 3d1c7eb14b07162eb2c35b49ebc32de72cadded2d54b9783921440aa317f772350252d0ce27ec54b621ff3ffcb1358b4c4074a2736917ac9670e9c28ac090c9f
7
+ data.tar.gz: f6e18d680ae236f3b0cf09a6d43a970bfef9b8ca82040ea4e8b368c65a1aa835c171b04743e688f04f9b6025a860cbc829b0f409d2166eb87e2161901684d16a
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # File: Gemfile
4
+ # Time-stamp: <2014-09-22 22:39:57 pierre>
5
+ # Copyright (C) 2014 Pierre Lecocq
6
+ # Description: Gemfile for PRRD library
7
+
8
+ source 'https://rubygems.org'
9
+
10
+ # Utils
11
+ gem 'rake'
12
+ gem 'rspec'
13
+ gem 'yard'
data/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # PRRD
2
+
3
+ A (simple) rrdtool ruby interface
4
+
5
+ ## Disclaimer
6
+
7
+ Hold on please, work in progress ...
8
+
9
+ ## Install
10
+
11
+ During the development process, there is no gem available. It will be packaged when the first stable release is reached.
12
+
13
+ To install PRRD, install dependencies and clone this repository:
14
+
15
+ ```
16
+ sudo gem install bundler
17
+ git clone https://github.com/pierre-lecocq/prrd
18
+ cd prrd
19
+ bundle install
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Require the library
25
+
26
+ `require '/path/to/prrd/lib/prdd.rb'`
27
+
28
+ ### Define a database
29
+
30
+ ```
31
+ database = PRRD::Database.new
32
+ database.path = '/path/to/your/directory/sample.rrd'
33
+
34
+ unless database.exists?
35
+
36
+ database.start = Time.now.to_i
37
+ database.step = 300
38
+
39
+ # Add datasources
40
+
41
+ ds = PRRD::Database::Datasource.new
42
+ ds.name = 'ds1'
43
+ ds.type = 'GAUGE'
44
+ ds.heartbeat = 600
45
+ ds.min = 0
46
+ ds.max = 'U'
47
+ database.add_datasource ds
48
+
49
+ ds = PRRD::Database::Datasource.new
50
+ ds.name = 'ds2'
51
+ ds.type = 'GAUGE'
52
+ ds.heartbeat = 600
53
+ ds.min = 0
54
+ ds.max = 'U'
55
+ database.add_datasource ds
56
+
57
+ # Add archives
58
+
59
+ ar = PRRD::Database::Archive.new
60
+ ar.cf = 'AVERAGE'
61
+ ar.xff = 0.5
62
+ ar.steps = 1
63
+ ar.rows = 576
64
+ database.add_archive ar
65
+
66
+ ar = PRRD::Database::Archive.new
67
+ ar.cf = 'AVERAGE'
68
+ ar.xff = 0.5
69
+ ar.steps = 6
70
+ ar.rows = 672
71
+ database.add_archive ar
72
+
73
+ ar = PRRD::Database::Archive.new
74
+ ar.cf = 'AVERAGE'
75
+ ar.xff = 0.5
76
+ ar.steps = 24
77
+ ar.rows = 732
78
+ database.add_archive ar
79
+
80
+ ar = PRRD::Database::Archive.new
81
+ ar.cf = 'AVERAGE'
82
+ ar.xff = 0.5
83
+ ar.steps = 144
84
+ ar.rows = 1460
85
+ database.add_archive ar
86
+
87
+ # Create
88
+
89
+ database.create
90
+
91
+ end
92
+ ```
93
+
94
+ ### Update the database
95
+
96
+ ```
97
+ value_ds1 = 125
98
+ value_ds2 = 38
99
+
100
+ database.update Time.now.to_i, value_ds1, value_ds2
101
+
102
+ ```
103
+
104
+ ### Generate the graph
105
+
106
+ ```
107
+ graph = PRRD::Graph.new
108
+ graph.path = '/path/to/your/directory/sample.png'
109
+ graph.database = database
110
+ graph.width = 600
111
+ graph.height = 300
112
+ graph.title = 'My graph'
113
+ graph.vertical_align = 'My vertical label'
114
+
115
+ # Optionally set colors
116
+
117
+ graph.add_color PRRD::Graph::Color.new colortag: 'BACK', color: '#151515'
118
+ graph.add_color PRRD::Graph::Color.new colortag: 'FONT', color: '#e5e5e5'
119
+ graph.add_color PRRD::Graph::Color.new colortag: 'CANVAS', color: '#252525'
120
+ graph.add_color PRRD::Graph::Color.new colortag: 'ARROW', color: '#ff0000'
121
+
122
+ # Set definitions
123
+
124
+ graph.add_definition PRRD::Graph::Definition.new vname: 'ds1', rrdfile: database.path, ds_name: 'ds1', cf: 'AVERAGE'
125
+ graph.add_definition PRRD::Graph::Definition.new vname: 'ds2', rrdfile: database.path, ds_name: 'ds2', cf: 'AVERAGE'
126
+
127
+ # Set lines
128
+
129
+ graph.add_line PRRD::Graph::Line.new value: 'ds1', width: 3, color: PRRD.color(:blue), legend: 'Ds1'
130
+ graph.add_line PRRD::Graph::Line.new value: 'ds2', color: PRRD.color(:blue), legend: 'Ds2'
131
+
132
+ # Create graph
133
+
134
+ graph.generate
135
+
136
+ ```
137
+
138
+ ## Syntaxes
139
+
140
+ For each element of a database or a graph, there are alternative syntaxes to create them.
141
+
142
+ Let's take an exemple with Datasources, but it is the same for Archives, Colors, Lines, Areas, ... and so on.
143
+
144
+ (Note: each example in the `scripts` folder use a different syntax as a showcase of all different ways to write PRRD scripts)
145
+
146
+ ### Object properties
147
+
148
+ ```
149
+ ds = PRRD::Database::Datasource.new
150
+ ds.name = 'ds1'
151
+ ds.type = 'GAUGE'
152
+ ds.heartbeat = 600
153
+ ds.min = 0
154
+ ds.max = 'U'
155
+ database.add_datasource ds
156
+
157
+ ds = PRRD::Database::Datasource.new
158
+ ds.name = 'ds2'
159
+ ds.type = 'GAUGE'
160
+ ds.heartbeat = 600
161
+ ds.min = 0
162
+ ds.max = 'U'
163
+ database.add_datasource ds
164
+ ```
165
+
166
+ ### Hashes
167
+
168
+ ```
169
+ ds = PRRD::Database::Datasource.new name: = 'ds1', type: 'GAUGE', heartbeat: 600, min: 0, max: 'U'
170
+ database.add_datasource ds
171
+
172
+ ds = PRRD::Database::Datasource.new name: = 'ds2', type: 'GAUGE', heartbeat: 600, min: 0, max: 'U'
173
+ database.add_datasource ds
174
+ ```
175
+
176
+ ### Array of hashes
177
+
178
+ ```
179
+ dss = [
180
+ PRRD::Database::Datasource.new({name: = 'ds1', type: 'GAUGE', heartbeat: 600, min: 0, max: 'U'}),
181
+ PRRD::Database::Datasource.new({name: = 'ds2', type: 'GAUGE', heartbeat: 600, min: 0, max: 'U'}),
182
+ ]
183
+
184
+ database.add_datasources dss
185
+ ```
186
+
187
+ ### Add objects
188
+
189
+ This syntax auto-detect the type and add it properly to the database or graph object
190
+
191
+ ```
192
+ database << PRRD::Database::Datasource.new({name: = 'ds1', type: 'GAUGE', heartbeat: 600, min: 0, max: 'U'})
193
+ graph << PRRD::Graph::Line.new({width: 2, value: = 'ds1', color: PRRD.color(:blue), legend: 'DS1'})
194
+ ```
195
+
196
+ ## Sample scripts
197
+
198
+ PRRD provides some real-world sample scripts located in the `scripts` directory.
199
+
200
+ - A `memory` script that graphs the consumption of memory and swap on your system
201
+ - A `cpu` script that graphs the usage of your CPU
202
+ - A `process` script that graphs the user and system processes
203
+ - A `network` script that graphs the send and recv packaged on your network interface (eth0)
204
+
205
+ To run them, simply type:
206
+
207
+ ```
208
+ ruby scripts/memory.rb
209
+ ruby scripts/cpu.rb
210
+ ruby scripts/process.rb
211
+ ruby scripts/network.rb
212
+ ```
213
+
214
+ Before that, you may be ask to copy `scripts/config.rb-example` to `scripts/config.rb` and edit it to fit to your needs
215
+
216
+ If you want to run them permanently, add these lines to your crontab (adpat *paths* and *username*):
217
+
218
+ ```
219
+ */5 * * * * username ruby /home/username/prrd/scripts/memory.rb > /dev/null
220
+ */5 * * * * username ruby /home/username/prrd/scripts/cpu.rb > /dev/null
221
+ */5 * * * * username ruby /home/username/prrd/scripts/process.rb > /dev/null
222
+ */5 * * * * username ruby /home/username/prrd/scripts/network.rb > /dev/null
223
+ ```
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # File: Rakefile
4
+ # Time-stamp: <2014-09-22 22:45:18 pierre>
5
+ # Copyright (C) 2014 Pierre Lecocq
6
+ # Description: Rakefile for PRRD library
7
+
8
+ task :default => :help
9
+ # rake help
10
+ task :help do
11
+ puts 'PRRD - rrdtool ruby interface'
12
+ puts "\n" + 'Available rake tasks:'
13
+ puts ' * test: run rspec tests'
14
+ puts ' * code: run rubocop to verify code quality'
15
+ puts ' * doc: run yard to generate documentation'
16
+ end
17
+
18
+ # rake test
19
+ require 'rspec/core/rake_task'
20
+ RSpec::Core::RakeTask.new(:test)
21
+
22
+ # rake code
23
+ require 'rubocop/rake_task'
24
+ desc 'Run RuboCop on the lib directory'
25
+ RuboCop::RakeTask.new(:code) do |task|
26
+ task.patterns = ['lib/**/*.rb']
27
+ task.fail_on_error = false
28
+ end
29
+
30
+ # rake doc
31
+ require 'yard'
32
+ YARD::Rake::YardocTask.new do |t|
33
+ t.files = ['lib/**/*.rb']
34
+ end
35
+ task :doc => :yard
data/lib/prrd.rb ADDED
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # File: prrd.rb
4
+ # Time-stamp: <2014-10-01 21:59:18 pierre>
5
+ # Copyright (C) 2014 Pierre Lecocq
6
+ # Description: RRD ruby module
7
+
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__))
9
+
10
+ # Main PRRD module
11
+ module PRRD
12
+ # Version
13
+ VERSION = [0, 2, 0].join('.')
14
+
15
+ # Class variables
16
+ @@debug_mode = false
17
+ @@colors = nil
18
+ @@bin = nil
19
+
20
+ # Activate debug mode
21
+ def self.activate_debug_mode
22
+ @@debug_mode = true
23
+ end
24
+
25
+ # Activate debug mode
26
+ def self.debug_mode
27
+ @@debug_mode
28
+ end
29
+
30
+ # Get rrdtool binary
31
+ # @return [String]
32
+ def self.bin
33
+ if @@bin.nil?
34
+ @@bin = `which rrdtool`.chomp
35
+ fail 'Install rrdtool. See http://oss.oetiker.ch/rrdtool/' if @@bin.nil?
36
+ end
37
+
38
+ @@bin
39
+ end
40
+
41
+ # Execute a command
42
+ # @param cmd [String]
43
+ # @param message [String, Nil]
44
+ # @return [String, Nil]
45
+ def self.execute(cmd, message = nil)
46
+ puts cmd if PRRD.debug_mode
47
+ `#{cmd}`
48
+
49
+ message if $CHILD_STATUS.nil? && !message.nil?
50
+ end
51
+
52
+ # Color class
53
+ class Color
54
+ # Accessors
55
+ attr_accessor :collection, :hexcode
56
+
57
+ # Constructor
58
+ # @param name [Symbol]
59
+ # @param tint [Symbol, nil]
60
+ # @param alpha [Symbol, nil]
61
+ def initialize(name, tint = nil, alpha = nil)
62
+ if name.is_a?(String) && name.include?('#')
63
+ @hexcode = name
64
+ else
65
+ @hexcode = to_hex(name, tint, alpha)
66
+ end
67
+ end
68
+
69
+ # Translate into hexcode
70
+ # @param name [Symbol]
71
+ # @param tint [Symbol, nil]
72
+ # @param alpha [Symbol, nil]
73
+ # @param [String]
74
+ def to_hex(name, tint = nil, alpha = nil)
75
+ if @collection.nil?
76
+ @collection = {
77
+ red: {light: '#EA644A', dark: '#CC3118'},
78
+ orange: {light: '#EC9D48', dark: '#CC7016'},
79
+ yellow: {light: '#ECD748', dark: '#C9B215'},
80
+ green: {light: '#54EC48', dark: '#24BC14'},
81
+ blue: {light: '#48C4EC', dark: '#1598C3'},
82
+ pink: {light: '#DE48EC', dark: '#B415C7'},
83
+ purple: {light: '#7648EC', dark: '#4D18E4'}
84
+ }
85
+ end
86
+
87
+ name = name.to_sym
88
+ tint = tint.nil? ? :light : tint.to_sym
89
+
90
+ fail "Unknown color #{name}" unless @collection.key? name
91
+ fail "Unknown tint #{tint}" unless @collection[name].key? tint
92
+
93
+ alpha.nil? ? @collection[name][tint] : @collection[name][tint] + alpha
94
+ end
95
+
96
+ # Darken the color
97
+ # @param percentage [Integer]
98
+ # @return [String]
99
+ def darken(percentage)
100
+ fail 'Can not operate on a non-hexadecimal color' if @hexcode.nil?
101
+
102
+ hexcode = @hexcode.gsub('#', '')
103
+ percentage = percentage.to_f / 100
104
+ rgb = hexcode.scan(/../).map { |c| c.hex }
105
+ rgb.map! { |c| (c.to_i * percentage).round }
106
+
107
+ "#%02x%02x%02x" % rgb
108
+ end
109
+
110
+ # Lighten the color
111
+ # @param percentage [Integer]
112
+ def lighten(percentage)
113
+ fail 'Can not operate on a non-hexadecimal color' if @hexcode.nil?
114
+
115
+ hexcode = @hexcode.gsub('#', '')
116
+ percentage = percentage.to_f / 100
117
+ rgb = hexcode.scan(/../).map { |c| c.hex }
118
+ rgb.map! { |c| [(c.to_i + 255 * percentage).round, 255].min }
119
+
120
+ "#%02x%02x%02x" % rgb
121
+ end
122
+
123
+ # String representation
124
+ def to_s
125
+ @hexcode
126
+ end
127
+ end
128
+
129
+ # Entity base class
130
+ class Entity
131
+ # Accessors
132
+ attr_accessor :data, :keys
133
+
134
+ # Constructor
135
+ def initialize(values = nil)
136
+ @data = {}
137
+
138
+ unless values.nil?
139
+ values.each do |k, v|
140
+ next unless @keys.include? k
141
+ send "#{k}=".to_sym, v
142
+ end
143
+ end
144
+ end
145
+
146
+ # Validate presence of keys in data collection
147
+ # @param keys [Array]
148
+ def validate_presence(*keys)
149
+ keys.each do |k|
150
+ fail 'Define a "%s" option' % k if !@data.key?(k) || @data[k].nil?
151
+ end
152
+ end
153
+
154
+ # Method missing
155
+ # @param m [Symbol]
156
+ # @param args [Array]
157
+ # @param block [Proc]
158
+ # @return [Boolean]
159
+ def method_missing(m, *args, &block)
160
+ ms = m.to_s
161
+ if ms.include? '='
162
+ ms = ms[0..-2]
163
+ if @keys.include? ms.to_sym
164
+ @data[ms.to_sym] = args[0]
165
+ return true
166
+ end
167
+ end
168
+
169
+ super
170
+ end
171
+ end
172
+ end
173
+
174
+ # Requires
175
+ require 'prrd/database'
176
+ require 'prrd/database/datasource'
177
+ require 'prrd/database/archive'
178
+
179
+ require 'prrd/graph'
180
+ require 'prrd/graph/definition'
181
+ require 'prrd/graph/colors'
182
+ require 'prrd/graph/area'
183
+ require 'prrd/graph/line'
184
+ require 'prrd/graph/print'
185
+ require 'prrd/graph/comment'
186
+ require 'prrd/graph/hrule'
187
+ require 'prrd/graph/vrule'
188
+ require 'prrd/graph/shift'
189
+ require 'prrd/graph/textalign'