gri 10.0.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 +7 -0
- data/.gitignore +7 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +132 -0
- data/Rakefile +5 -0
- data/bin/grapher +17 -0
- data/bin/gri +5 -0
- data/bin/gricast +17 -0
- data/bin/grispark +5 -0
- data/bin/griwalk +9 -0
- data/bin/trad +19 -0
- data/bin/trad-http +17 -0
- data/gri.gemspec +21 -0
- data/lib/fluent/plugin/out_gri.rb +56 -0
- data/lib/gri/api.rb +28 -0
- data/lib/gri/app_collector.rb +154 -0
- data/lib/gri/app_walker.rb +23 -0
- data/lib/gri/blank.rb +49 -0
- data/lib/gri/builtindefs.rb +211 -0
- data/lib/gri/cast.rb +84 -0
- data/lib/gri/cgraph.rb +37 -0
- data/lib/gri/clist.rb +163 -0
- data/lib/gri/collector.rb +284 -0
- data/lib/gri/config.rb +134 -0
- data/lib/gri/ds_list.rb +166 -0
- data/lib/gri/format_helper.rb +112 -0
- data/lib/gri/gparams.rb +43 -0
- data/lib/gri/graph.rb +239 -0
- data/lib/gri/grapher.rb +70 -0
- data/lib/gri/ldb.rb +160 -0
- data/lib/gri/list.rb +242 -0
- data/lib/gri/log.rb +140 -0
- data/lib/gri/loop.rb +109 -0
- data/lib/gri/ltsv.rb +58 -0
- data/lib/gri/main.rb +107 -0
- data/lib/gri/mlog.rb +22 -0
- data/lib/gri/mmsgpack.rb +57 -0
- data/lib/gri/msnmp.rb +601 -0
- data/lib/gri/page.rb +235 -0
- data/lib/gri/pcollector.rb +209 -0
- data/lib/gri/plugin.rb +75 -0
- data/lib/gri/plugin/bootstrap.rb +65 -0
- data/lib/gri/plugin/cisco.rb +98 -0
- data/lib/gri/plugin/exec_collector.rb +89 -0
- data/lib/gri/plugin/juniper.rb +5 -0
- data/lib/gri/plugin/netsnmp.rb +8 -0
- data/lib/gri/plugin/ucdavis.rb +176 -0
- data/lib/gri/plugin/writer_fluentd.rb +26 -0
- data/lib/gri/polling_unit.rb +88 -0
- data/lib/gri/q.rb +5 -0
- data/lib/gri/request.rb +29 -0
- data/lib/gri/rrd.rb +438 -0
- data/lib/gri/scheduler.rb +68 -0
- data/lib/gri/sgraph.rb +147 -0
- data/lib/gri/spark.rb +94 -0
- data/lib/gri/tra_collector.rb +80 -0
- data/lib/gri/trad.rb +170 -0
- data/lib/gri/updater.rb +201 -0
- data/lib/gri/util_daemon.rb +19 -0
- data/lib/gri/util_marshal.rb +13 -0
- data/lib/gri/utils.rb +63 -0
- data/lib/gri/vendor.rb +76 -0
- data/lib/gri/version.rb +3 -0
- data/lib/gri/wmain.rb +67 -0
- data/lib/gri/writer.rb +184 -0
- data/mcollector +47 -0
- data/test/mock.rb +60 -0
- data/test/root/gra/.sysdb/sysdb.txt +3 -0
- data/test/root/gra/testhost/.records.txt +2 -0
- data/test/root/if.def +2 -0
- data/test/root/test.conf +4 -0
- data/test/root/testtab +9 -0
- data/test/root/testtab2 +2 -0
- data/test/root/tra/testhost/_/20130614 +20 -0
- data/test/test_app.rb +58 -0
- data/test/test_builtindefs.rb +24 -0
- data/test/test_collector.rb +58 -0
- data/test/test_config.rb +62 -0
- data/test/test_ds_list.rb +48 -0
- data/test/test_exec_collector.rb +33 -0
- data/test/test_format_helper.rb +68 -0
- data/test/test_graph.rb +69 -0
- data/test/test_ldb.rb +29 -0
- data/test/test_list.rb +65 -0
- data/test/test_log.rb +16 -0
- data/test/test_loop.rb +35 -0
- data/test/test_ltsv.rb +38 -0
- data/test/test_main.rb +19 -0
- data/test/test_mmsgpack.rb +27 -0
- data/test/test_msnmp.rb +147 -0
- data/test/test_page.rb +51 -0
- data/test/test_pcollector.rb +71 -0
- data/test/test_plugin.rb +62 -0
- data/test/test_plugin_cisco.rb +23 -0
- data/test/test_polling_unit.rb +58 -0
- data/test/test_request.rb +26 -0
- data/test/test_rrd.rb +53 -0
- data/test/test_rrd_updater.rb +139 -0
- data/test/test_scheduler.rb +31 -0
- data/test/test_tra_collector.rb +40 -0
- data/test/test_trad.rb +33 -0
- data/test/test_util_marshal.rb +17 -0
- data/test/test_utils.rb +15 -0
- data/test/test_vendor.rb +40 -0
- data/test/test_writer.rb +33 -0
- data/test/unittest_helper.rb +27 -0
- metadata +208 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'gri/writer'
|
2
|
+
unless Object.const_defined? :MessagePack
|
3
|
+
require 'gri/mmsgpack'
|
4
|
+
end
|
5
|
+
|
6
|
+
module GRI
|
7
|
+
class FluentWriter < Writer
|
8
|
+
TYPES['fluent'] = self
|
9
|
+
TYPES['fluentd'] = self
|
10
|
+
|
11
|
+
def initialize options={}
|
12
|
+
@options = options
|
13
|
+
host = options[:fluent_host]
|
14
|
+
@sock = TCPSocket.new host, 24224
|
15
|
+
end
|
16
|
+
|
17
|
+
def write records
|
18
|
+
time = Time.now.to_i
|
19
|
+
for record in records
|
20
|
+
tag = @options[:fluent_tag] || "gri.#{record['_key']}"
|
21
|
+
s = [tag, time, record].to_msgpack
|
22
|
+
@sock.write s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module GRI
|
2
|
+
class PollingUnit
|
3
|
+
UNITS = {}
|
4
|
+
|
5
|
+
attr_reader :name, :cat, :oids
|
6
|
+
attr_accessor :dhash
|
7
|
+
alias :defs :dhash
|
8
|
+
|
9
|
+
def self.all_units
|
10
|
+
if UNITS.empty?
|
11
|
+
for name, dhash in DEFS
|
12
|
+
next unless String === name
|
13
|
+
pucat = dhash[:cat] || dhash[:pucat] ||
|
14
|
+
(dhash[:tdb] and dhash[:tdb].first.intern) || name.intern
|
15
|
+
puclass = dhash[:puclass]
|
16
|
+
if puclass and Object.const_defined?(puclass + 'PollingUnit')
|
17
|
+
klass = eval(puclass + 'PollingUnit')
|
18
|
+
else
|
19
|
+
klass = self
|
20
|
+
end
|
21
|
+
pu = klass.new name, pucat
|
22
|
+
pu.dhash = dhash
|
23
|
+
pu.set_oids dhash[:oid]
|
24
|
+
|
25
|
+
self::UNITS[name] = pu
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self::UNITS
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize name, cat
|
32
|
+
@name = name
|
33
|
+
@cat = cat
|
34
|
+
@d_p = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_oids names
|
38
|
+
@oids = (names || []).map {|name|
|
39
|
+
(oid = SNMP::OIDS[name]) ? BER.enc_v_oid(oid) :
|
40
|
+
(Log.debug "No such OID: #{name}"; nil)
|
41
|
+
}.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
def feed wh, enoid, tag, val
|
45
|
+
if (feed_proc = dhash[:feed])
|
46
|
+
puts " feed_proc #{[enid, tag, val].inspect}" if @d_p
|
47
|
+
feed_proc.call wh, enoid, tag, val
|
48
|
+
else
|
49
|
+
if enoid.getbyte(-2) < 128
|
50
|
+
ind = enoid.getbyte(-1)
|
51
|
+
if ind == 0
|
52
|
+
oid_ind = enoid
|
53
|
+
else
|
54
|
+
oid_ind = enoid[0..-2]
|
55
|
+
end
|
56
|
+
else
|
57
|
+
if enoid.getbyte(-3) < 128
|
58
|
+
ind = ((enoid.getbyte(-2) & 0x7f) << 7) + enoid.getbyte(-1)
|
59
|
+
oid_ind = enoid[0..-3]
|
60
|
+
else
|
61
|
+
tmpary = BER.dec_oid enoid
|
62
|
+
oid_ind = BER.enc_v_oid(tmpary[0..-2].join('.'))
|
63
|
+
ind = tmpary[-1]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if (sym_oid = SNMP::ROIDS[oid_ind])
|
67
|
+
(conv_val_proc = dhash[:conv_val]) and
|
68
|
+
(val = conv_val_proc.call(sym_oid, val))
|
69
|
+
(wh[ind] ||= {})[sym_oid] = val
|
70
|
+
if @d_p
|
71
|
+
wh[ind]['_d'] = true
|
72
|
+
puts " feed #{[sym_oid, ind, tag, val].inspect}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fix_workhash workhash
|
79
|
+
if (c = dhash[:fix_workhash])
|
80
|
+
c.call workhash
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def inspect
|
85
|
+
"#<PU:#{@name}>"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/gri/q.rb
ADDED
data/lib/gri/request.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
require 'gri/gparams'
|
3
|
+
|
4
|
+
module GRI
|
5
|
+
class Request < Rack::Request
|
6
|
+
def query_string=(s)
|
7
|
+
@query_string = s
|
8
|
+
@gparams = @params = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
alias query_string0 query_string
|
12
|
+
def query_string
|
13
|
+
@query_string || query_string0
|
14
|
+
end
|
15
|
+
|
16
|
+
def gparams
|
17
|
+
@gparams ||= gparse_query query_string
|
18
|
+
end
|
19
|
+
|
20
|
+
def gparse_query qs
|
21
|
+
params = GParams.new
|
22
|
+
(qs || '').split(/[&;] */n).each {|item|
|
23
|
+
k, v = item.split('=', 2).map {|s| Rack::Utils.unescape s}
|
24
|
+
params[k] = v
|
25
|
+
}
|
26
|
+
params
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/gri/rrd.rb
ADDED
@@ -0,0 +1,438 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
class RRDError < Exception; end
|
4
|
+
|
5
|
+
module RRDm
|
6
|
+
extend RRDm
|
7
|
+
|
8
|
+
@@rrdtool_path = (Dir.glob('/usr/local/rrdtool-*/bin/rrdtool').sort.reverse +
|
9
|
+
['/usr/local/bin/rrdtool', '/usr/bin/rrdtool']).find {|path|
|
10
|
+
File.executable? path.untaint
|
11
|
+
}
|
12
|
+
|
13
|
+
attr_reader :version
|
14
|
+
|
15
|
+
def start rrdtool_path=nil
|
16
|
+
rrdtool_path ||= @@rrdtool_path
|
17
|
+
raise RuntimeError, 'rrdtool is already running' if @sequence
|
18
|
+
unless rrdtool_path and File.exist?(rrdtool_path)
|
19
|
+
raise Exception, "rrdtool #{rrdtool_path} not found"
|
20
|
+
end
|
21
|
+
@sequence = 'S'
|
22
|
+
@last_cmd = nil
|
23
|
+
|
24
|
+
@in, @out, @err = Open3.popen3("#{rrdtool_path} -")
|
25
|
+
@in.sync = true
|
26
|
+
@out.sync = true
|
27
|
+
|
28
|
+
cmd 'version'
|
29
|
+
line, = read
|
30
|
+
@version, = line.scan(/^RRDtool\s+(\S+)/)[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def running?
|
34
|
+
@sequence
|
35
|
+
end
|
36
|
+
|
37
|
+
def read out=nil
|
38
|
+
unless @sequence == 'C'
|
39
|
+
raise RuntimeError, 'RRDm.read can only be called after RRDm.cmd'
|
40
|
+
end
|
41
|
+
@sequence == 'R'
|
42
|
+
lines = []
|
43
|
+
errline = nil
|
44
|
+
|
45
|
+
while line = @out.gets
|
46
|
+
if line =~ /^ERROR/
|
47
|
+
errline = line.gsub(/\n/, "\\n")
|
48
|
+
raise RuntimeError, errline
|
49
|
+
elsif line =~ /^OK u:([\d\.]+) s:([\d\.]+) r:([\d\.]+)/
|
50
|
+
sys, user, real = $1.to_f, $2.to_f, $3.to_f
|
51
|
+
if errline
|
52
|
+
raise RuntimeError, errline
|
53
|
+
else
|
54
|
+
return [lines.join(''), sys, user, real]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
if out
|
58
|
+
out.write line
|
59
|
+
else
|
60
|
+
lines.push line
|
61
|
+
end
|
62
|
+
end
|
63
|
+
raise RuntimeError, 'unexpected EOF'
|
64
|
+
end
|
65
|
+
|
66
|
+
def cmd(*args)
|
67
|
+
@sequence = 'C'
|
68
|
+
cmd = args.join(' ')
|
69
|
+
@in.print cmd, "\n"
|
70
|
+
@last_cmd = cmd
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
@sequence = nil
|
75
|
+
@in.close
|
76
|
+
@out.close
|
77
|
+
@err.close
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class RRD
|
82
|
+
attr_accessor :width, :height
|
83
|
+
attr_accessor :title, :vertical_label
|
84
|
+
attr_accessor :imgformat
|
85
|
+
attr_accessor :lower_limit
|
86
|
+
attr_accessor :x_grid_hash
|
87
|
+
attr_accessor :fonts
|
88
|
+
attr_reader :created_p
|
89
|
+
attr_reader :ds_ary
|
90
|
+
attr_reader :version
|
91
|
+
attr_writer :show_graph_date
|
92
|
+
|
93
|
+
def initialize address=nil, base_dir=nil
|
94
|
+
@address = address
|
95
|
+
@base_dir = base_dir
|
96
|
+
|
97
|
+
@imgformat = 'PNG'
|
98
|
+
@update_buf = []
|
99
|
+
@x_grid_hash = {}
|
100
|
+
@show_graph_date = false
|
101
|
+
@fonts = []
|
102
|
+
RRDm.start unless RRDm.running?
|
103
|
+
@version = (RRDm.version =~ /\A(1\.\d)\./) ? $1 : '1.0'
|
104
|
+
end
|
105
|
+
|
106
|
+
def set_create_args *args
|
107
|
+
@rrdname = args.shift
|
108
|
+
if @rrdname
|
109
|
+
@created_p = File.exist? @rrdname
|
110
|
+
@args = args
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def remove_base_dir *args
|
115
|
+
return args unless @base_dir
|
116
|
+
if @base_dir[-1, 1] == ?/
|
117
|
+
base_dir = @base_dir
|
118
|
+
else
|
119
|
+
base_dir = @base_dir + '/'
|
120
|
+
end
|
121
|
+
re = /\A#{base_dir}/
|
122
|
+
args.map {|arg| arg.sub(re, '')}
|
123
|
+
end
|
124
|
+
|
125
|
+
def create start=nil, step=nil, *args
|
126
|
+
str = ''
|
127
|
+
if start
|
128
|
+
start = start.to_i
|
129
|
+
str = "--start #{start} "
|
130
|
+
end
|
131
|
+
if step
|
132
|
+
str += "--step #{step}"
|
133
|
+
end
|
134
|
+
RRDm.cmd 'create', @rrdname, str, *args
|
135
|
+
return RRDm.read
|
136
|
+
end
|
137
|
+
private :create
|
138
|
+
|
139
|
+
def buffered_update(*args)
|
140
|
+
res = flush_buffer if @update_buf.size > 40
|
141
|
+
@update_buf += args
|
142
|
+
res
|
143
|
+
end
|
144
|
+
|
145
|
+
def flush_buffer v=false
|
146
|
+
if @update_buf.size > 0
|
147
|
+
begin
|
148
|
+
unless @created_p
|
149
|
+
create *@args
|
150
|
+
@created_p = true
|
151
|
+
end
|
152
|
+
res = update *@update_buf
|
153
|
+
end
|
154
|
+
@update_buf = []
|
155
|
+
end
|
156
|
+
res
|
157
|
+
end
|
158
|
+
|
159
|
+
def update(*args)
|
160
|
+
daemon = @address ? " --daemon #{@address}" : ''
|
161
|
+
path = remove_base_dir @rrdname
|
162
|
+
RRDm.cmd "update#{daemon}", path.first, *args
|
163
|
+
begin
|
164
|
+
str, = RRDm.read
|
165
|
+
rescue RuntimeError => e
|
166
|
+
if e.message =~ /last update time is (\d+)/
|
167
|
+
last_update = $1.to_i
|
168
|
+
pargs = []
|
169
|
+
args.each {|arg|
|
170
|
+
if arg.split(':')[0].to_i > last_update
|
171
|
+
pargs.push arg
|
172
|
+
end
|
173
|
+
}
|
174
|
+
if pargs.size == 0
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
args = pargs
|
178
|
+
RRDm.cmd "update#{daemon}", path, *args
|
179
|
+
str, = RRDm.read rescue nil
|
180
|
+
else
|
181
|
+
Log.error "#{@rrdname}: #{$!}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
lines = str.split(/\n/).select {|line| line =~ /^\[/} if str
|
185
|
+
lines
|
186
|
+
end
|
187
|
+
|
188
|
+
def graph fname, starttime, endtime, *misc_args
|
189
|
+
starttime = starttime.to_i
|
190
|
+
endtime = endtime.to_i
|
191
|
+
if misc_args.first.kind_of? Symbol
|
192
|
+
cmd = misc_args.shift.to_s
|
193
|
+
else
|
194
|
+
daemon = @address ? " --daemon #{@address}" : ''
|
195
|
+
cmd = "graph#{daemon}"
|
196
|
+
end
|
197
|
+
args = [cmd, fname, '--start', starttime, '--end', endtime]
|
198
|
+
args.push '--slope-mode' if @version >= '1.2'
|
199
|
+
args.push '--width ' + @width.to_s if @width
|
200
|
+
args.push '--height ' + @height.to_s if @height
|
201
|
+
args.push '--lower-limit ' + @lower_limit.to_s if @lower_limit
|
202
|
+
args.push '--imgformat ' + @imgformat
|
203
|
+
args.push '--title ' + @title if @title
|
204
|
+
args.push '--vertical-label ' + @vertical_label if @vertical_label
|
205
|
+
if @version >= '1.3'
|
206
|
+
for fstr in @fonts
|
207
|
+
(fstr =~ /^(DEFAULT|TITLE|AXIS|UNIT|LEGEND):(\d+):/) and
|
208
|
+
args.push "-n \"#{fstr}\""
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
dt = endtime - starttime
|
213
|
+
vtime = Time.at(starttime)
|
214
|
+
vcolor = '#ff7f7f'
|
215
|
+
xgrid = nil
|
216
|
+
if dt < 3 * 3600
|
217
|
+
vtime = Time.local(vtime.year, vtime.mon, vtime.day) + 24*3600
|
218
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}" if vtime.to_i < endtime
|
219
|
+
xgrid = 'MINUTE:10:HOUR:1:MINUTE:10:0:%H:%M'
|
220
|
+
elsif dt < 12 * 3600
|
221
|
+
vtime = Time.local(vtime.year, vtime.mon, vtime.day) + 24*3600
|
222
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}" if vtime.to_i < endtime
|
223
|
+
xgrid = 'MINUTE:30:HOUR:1:HOUR:1:0:%H:%M'
|
224
|
+
elsif dt < 6 * 24 * 3600
|
225
|
+
vtime = Time.local(vtime.year, vtime.mon, vtime.day) + 24*3600
|
226
|
+
while vtime.to_i < endtime
|
227
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}"
|
228
|
+
vtime += 24*3600
|
229
|
+
end
|
230
|
+
xgrid = 'HOUR:1:HOUR:6:HOUR:6:0:%H:%M'
|
231
|
+
elsif dt < 14 * 24 * 3600
|
232
|
+
tmptime = vtime + ((8 - vtime.wday) % 7)*24*3600
|
233
|
+
vtime = Time.local(tmptime.year, tmptime.mon, tmptime.day)
|
234
|
+
while vtime.to_i < endtime
|
235
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}"
|
236
|
+
vtime += 7*24*3600
|
237
|
+
end
|
238
|
+
xgrid = 'HOUR:6:DAY:1:DAY:1:86400:%a'
|
239
|
+
elsif dt < 90 * 24 * 3600
|
240
|
+
tmptime = Time.local(vtime.year, vtime.mon) + 31*24*3600 + 3610
|
241
|
+
vtime = Time.local(tmptime.year, tmptime.mon)
|
242
|
+
while vtime.to_i < endtime
|
243
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}"
|
244
|
+
tmptime = vtime + 31*24*3600 + 3610
|
245
|
+
vtime = Time.local(tmptime.year, tmptime.mon, 1)
|
246
|
+
end
|
247
|
+
xgrid = 'DAY:1:WEEK:1:WEEK:1:86400:%m/%d'
|
248
|
+
else
|
249
|
+
vtime = Time.local(vtime.year+1)
|
250
|
+
while vtime.to_i < endtime
|
251
|
+
args.push "VRULE:#{vtime.to_i}#{vcolor}"
|
252
|
+
vtime = Time.local(vtime.year+1)
|
253
|
+
end
|
254
|
+
xgrid = 'MONTH:3:YEAR:1:YEAR:1:31536000:%Y' if dt > 400 * 24 * 3600
|
255
|
+
end
|
256
|
+
args.push "--x-grid \"#{xgrid}\"" if xgrid
|
257
|
+
|
258
|
+
if @show_graph_date
|
259
|
+
cstr = "COMMENT:" +
|
260
|
+
Time.at(starttime).strftime('"%Y/%m/%d %H:%M - ') +
|
261
|
+
Time.at(endtime).strftime('%Y/%m/%d %H:%M\n"')
|
262
|
+
args.push cstr
|
263
|
+
end
|
264
|
+
|
265
|
+
args += misc_args
|
266
|
+
RRDm.cmd args
|
267
|
+
return RRDm.read
|
268
|
+
end
|
269
|
+
|
270
|
+
def fetch cf, resolution=nil, starttime=nil, endtime=nil
|
271
|
+
args = []
|
272
|
+
if resolution
|
273
|
+
resolution = resolution.to_i
|
274
|
+
if starttime and endtime
|
275
|
+
starttime = starttime.to_i / resolution * resolution
|
276
|
+
endtime = endtime.to_i / resolution * resolution
|
277
|
+
end
|
278
|
+
args.push ['--resolution', resolution]
|
279
|
+
end
|
280
|
+
args.push ['--start', starttime.to_i] if starttime
|
281
|
+
args.push ['--end', endtime.to_i] if endtime
|
282
|
+
RRDm.cmd 'fetch', @rrdname, cf, *args
|
283
|
+
str, = RRDm.read
|
284
|
+
collect = []
|
285
|
+
s = nil #XXX
|
286
|
+
for line in str.split("\n")
|
287
|
+
timestr, *remain = line.split
|
288
|
+
time = timestr.to_i
|
289
|
+
if time > 0
|
290
|
+
collect.push [Time.at(time),
|
291
|
+
remain.collect {|s|
|
292
|
+
if s =~ /^nan$/i
|
293
|
+
nil
|
294
|
+
else
|
295
|
+
s.to_f
|
296
|
+
end
|
297
|
+
}]
|
298
|
+
else
|
299
|
+
ds_ary = line.split
|
300
|
+
ds_ary.shift
|
301
|
+
@ds_ary = ds_ary if ds_ary.size > 0
|
302
|
+
end
|
303
|
+
end
|
304
|
+
return collect
|
305
|
+
end
|
306
|
+
|
307
|
+
def tune args
|
308
|
+
RRDm.cmd 'tune', @rrdname, *args
|
309
|
+
str, = RRDm.read
|
310
|
+
return str.split("\n")
|
311
|
+
end
|
312
|
+
|
313
|
+
def resize num, deltasize
|
314
|
+
if deltasize >= 0
|
315
|
+
rrcmd = 'GROW'
|
316
|
+
else
|
317
|
+
rrcmd = 'SHRINK'
|
318
|
+
end
|
319
|
+
RRDm.cmd 'resize', @rrdname, num, rrcmd, deltasize.abs
|
320
|
+
str, = RRDm.read
|
321
|
+
File.rename 'resize.rrd', @rrdname
|
322
|
+
return str.split("\n")
|
323
|
+
end
|
324
|
+
|
325
|
+
def info
|
326
|
+
RRDm.cmd 'info', @rrdname
|
327
|
+
str, = RRDm.read
|
328
|
+
return str.split("\n")
|
329
|
+
end
|
330
|
+
|
331
|
+
def dump dst=nil
|
332
|
+
tmp_path = dst || "/tmp/rrdtmp#{$$}.xml"
|
333
|
+
open(tmp_path, 'w') {|out|
|
334
|
+
RRDm.cmd 'dump', @rrdname#, tmp_path
|
335
|
+
str, = RRDm.read out
|
336
|
+
}
|
337
|
+
return tmp_path
|
338
|
+
end
|
339
|
+
|
340
|
+
def restore src=nil
|
341
|
+
tmp_path = src
|
342
|
+
RRDm.cmd 'restore', tmp_path, @rrdname
|
343
|
+
str, = RRDm.read
|
344
|
+
return tmp_path
|
345
|
+
end
|
346
|
+
|
347
|
+
def xport starttime, endtime, *misc_args
|
348
|
+
starttime = starttime.to_i
|
349
|
+
endtime = endtime.to_i
|
350
|
+
cmd = "xport#{@address ? " --daemon #{@address}" : ''}"
|
351
|
+
args = [cmd, '--json', '--start', starttime, '--end', endtime] + misc_args
|
352
|
+
RRDm.cmd args
|
353
|
+
str, = RRDm.read
|
354
|
+
return str
|
355
|
+
end
|
356
|
+
|
357
|
+
def rrainfo
|
358
|
+
ary = info
|
359
|
+
rra = []
|
360
|
+
step, = ary[2].scan(/^step = (\d+)$/)[0]
|
361
|
+
if step
|
362
|
+
for line in ary
|
363
|
+
if line =~ /^rra\[(\d+)\]\.(.*)/
|
364
|
+
num = $1.to_i
|
365
|
+
remain = $2
|
366
|
+
#p [$1, remain]
|
367
|
+
rra[num] = [] unless rra[num]
|
368
|
+
case remain
|
369
|
+
when /^cf = "(\w+)"/
|
370
|
+
rra[num][0] = $1
|
371
|
+
when /^rows = (\d+)/
|
372
|
+
rra[num][1] = $1.to_i
|
373
|
+
when /^pdp_per_row = (\d+)/
|
374
|
+
rra[num][2] = $1.to_i
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
return step, rra
|
380
|
+
end
|
381
|
+
|
382
|
+
def graphgen stime, etime, args
|
383
|
+
tmp_file = "/tmp/rrdtmp#{$$}"
|
384
|
+
img = nil
|
385
|
+
graph tmp_file, stime, etime, args
|
386
|
+
open(tmp_file) {|f| img = f.read}
|
387
|
+
File.unlink tmp_file
|
388
|
+
img
|
389
|
+
end
|
390
|
+
|
391
|
+
def self.defstr rrdpaths, ds, cf, cname, line, color, legend,
|
392
|
+
mag=1, lower_bound=nil, upper_bound=nil
|
393
|
+
expr = []
|
394
|
+
st = {}
|
395
|
+
n = 0
|
396
|
+
|
397
|
+
limitstr = if lower_bound and upper_bound and (lower_bound != upper_bound)
|
398
|
+
",#{lower_bound},#{upper_bound},LIMIT"
|
399
|
+
elsif lower_bound
|
400
|
+
",DUP,#{lower_bound},GE,EXC,UNKN,IF"
|
401
|
+
else
|
402
|
+
''
|
403
|
+
end
|
404
|
+
if rrdpaths.size > 1
|
405
|
+
vnames = []
|
406
|
+
for rrdpath in rrdpaths
|
407
|
+
basename = File.basename rrdpath, '.rrd'
|
408
|
+
vname = "v#{st[basename] ||= (n+=1)}#{ds}"
|
409
|
+
vnames.push vname
|
410
|
+
expr.push "DEF:#{vname}=#{rrdpath}:#{ds}:#{cf} "
|
411
|
+
end
|
412
|
+
tmpstr = "CDEF:#{cname}=" +
|
413
|
+
vnames.map {|vname|
|
414
|
+
"#{vname},UN,0,#{vname},IF,#{mag},*#{limitstr}"
|
415
|
+
}.join(',') + ',+' * (vnames.size-1)
|
416
|
+
expr.push tmpstr
|
417
|
+
#expr.push ',FLOOR' if ds =~ /(in|out)ucast/
|
418
|
+
else
|
419
|
+
rrdpath, = rrdpaths
|
420
|
+
expr.push "DEF:v#{cname}=#{rrdpath}:#{ds}:#{cf} "
|
421
|
+
expr.push "CDEF:#{cname}=v#{cname}#{limitstr},#{mag},* "
|
422
|
+
end
|
423
|
+
|
424
|
+
if line == 'XPORT'
|
425
|
+
expr.push " XPORT:#{cname}:\"#{legend}\""
|
426
|
+
else
|
427
|
+
expr.push " #{line}:#{cname}#{color}"
|
428
|
+
unless legend == '-'
|
429
|
+
esc_legend = legend.gsub(':', '\:')
|
430
|
+
expr.push ":\"#{esc_legend}\" "
|
431
|
+
expr.push "GPRINT:#{cname}:MAX:\"(max\\:%.2lf%s\" "
|
432
|
+
expr.push "GPRINT:#{cname}:AVERAGE:\"avg\\:%.2lf%s\" "
|
433
|
+
expr.push "GPRINT:#{cname}:LAST:\"last\\:%.2lf%s)\""
|
434
|
+
end
|
435
|
+
end
|
436
|
+
return expr.join('')
|
437
|
+
end
|
438
|
+
end
|