RubyRRDtool 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +9 -0
- data/README +64 -0
- data/Rakefile +38 -0
- data/examples/function_test.rb +134 -0
- data/examples/minmax.rb +60 -0
- data/extconf.rb +29 -0
- data/rrd_addition.h +47 -0
- data/rubyrrdtool.c +1093 -0
- data/test/test_rrdtool.rb +172 -0
- metadata +62 -0
data/Manifest.txt
ADDED
data/README
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# README -- ruby librrd bindings
|
2
|
+
|
3
|
+
Authors: David Bacher <drbacher at alum.mit.edu>
|
4
|
+
Mark Probert <probertm at acm.org>
|
5
|
+
based on work by Miles Egan <miles at caddr.com>
|
6
|
+
|
7
|
+
|
8
|
+
== Introduction
|
9
|
+
|
10
|
+
rubyrrdtool provides ruby bindings for RRD functions (via librrd), with
|
11
|
+
functionality comparable to the native perl bindings. See examples/minmax.rb
|
12
|
+
or the unit tests in the test directory for scripts that exercise the
|
13
|
+
rrdtool functions.
|
14
|
+
|
15
|
+
|
16
|
+
== Installation
|
17
|
+
|
18
|
+
rubyrrdtool requires RRDtool version 1.2 or later. Some RRD functions such
|
19
|
+
as rrddump are only available with the latest RRDtool.
|
20
|
+
|
21
|
+
Installation is standard. If you've installed the gem, you should be ready
|
22
|
+
to go. Otherwise, simply run:
|
23
|
+
|
24
|
+
ruby extconf.rb
|
25
|
+
make
|
26
|
+
make install
|
27
|
+
|
28
|
+
I hope this works for you. Please let me know if you have any problems or
|
29
|
+
suggestions.
|
30
|
+
|
31
|
+
Thanks to Tobi for rrdtool!
|
32
|
+
|
33
|
+
|
34
|
+
== To do
|
35
|
+
|
36
|
+
* Documentation
|
37
|
+
* Build an interface that feels more ruby-like around this simple functional
|
38
|
+
translation
|
39
|
+
|
40
|
+
|
41
|
+
== License
|
42
|
+
|
43
|
+
(the MIT license)
|
44
|
+
|
45
|
+
Copyright (c) 2006
|
46
|
+
|
47
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
48
|
+
a copy of this software and associated documentation files (the
|
49
|
+
"Software"), to deal in the Software without restriction, including
|
50
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
51
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
52
|
+
permit persons to whom the Software is furnished to do so, subject to
|
53
|
+
the following conditions:
|
54
|
+
|
55
|
+
The above copyright notice and this permission notice shall be
|
56
|
+
included in all copies or substantial portions of the Software.
|
57
|
+
|
58
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
59
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
60
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
61
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
62
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
63
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
64
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'hoe'
|
6
|
+
|
7
|
+
RUBY_RRDTOOL_VERSION = '0.6.0'
|
8
|
+
|
9
|
+
Hoe.new("RubyRRDtool", RUBY_RRDTOOL_VERSION) do |p|
|
10
|
+
p.rubyforge_name = "rubyrrdtool"
|
11
|
+
p.summary = "Ruby language binding for RRD tool version 1.2+"
|
12
|
+
p.description = p.paragraphs_of('README', 2..3).join("\n\n")
|
13
|
+
|
14
|
+
p.url = "http://rubyforge.org/projects/rubyrrdtool/"
|
15
|
+
|
16
|
+
p.author = [ "David Bacher", "Mark Probert" ]
|
17
|
+
p.email = "drbacher @nospam@ alum dot mit dot edu"
|
18
|
+
|
19
|
+
p.spec_extras = { 'extensions' => 'extconf.rb' }
|
20
|
+
|
21
|
+
p.changes =<<EOC
|
22
|
+
* applied patches (thanks to Hrvoje Marjanovic, Akihiro Sagawa and Thorsten von Eicken)
|
23
|
+
* changed version, graph, xport methods to be class methods
|
24
|
+
* removed dump method from pre two-arg-dump rrdtool versions
|
25
|
+
* fixed compiler warnings in debug output
|
26
|
+
* hoe-ified Rakefile
|
27
|
+
EOC
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build RRD driver"
|
31
|
+
task :build do
|
32
|
+
puts `[ -e Makefile ] || ruby extconf.rb; make`
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Rebuild RRD driver"
|
36
|
+
task :rebuild do
|
37
|
+
puts `ruby extconf.rb; make clean all`
|
38
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# $Id: function_test.rb,v 1.2 2006/10/18 21:43:38 dbach Exp $
|
3
|
+
# Driver does not carry cash.
|
4
|
+
|
5
|
+
# insert the lib directory at the front of the path to pick up
|
6
|
+
# the latest build -- useful for testing during development
|
7
|
+
$:.unshift '../lib'
|
8
|
+
|
9
|
+
require 'RRDtool'
|
10
|
+
|
11
|
+
name = "test"
|
12
|
+
rrdname = "#{name}.rrd"
|
13
|
+
start = Time.now.to_i
|
14
|
+
|
15
|
+
rrd = RRDtool.new(rrdname)
|
16
|
+
puts "created new RRD database -> #{rrd.rrdname}"
|
17
|
+
|
18
|
+
|
19
|
+
# ---------------------------------------------
|
20
|
+
# Version
|
21
|
+
# ---------------------------------------------
|
22
|
+
puts "RRD Version "
|
23
|
+
n = RRDtool.version
|
24
|
+
puts "version() returned #{(n.nil?) ? "nil" : n}"
|
25
|
+
puts
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
# ---------------------------------------------
|
31
|
+
# Create
|
32
|
+
# ---------------------------------------------
|
33
|
+
puts "creating #{rrdname}"
|
34
|
+
n = rrd.create(
|
35
|
+
300, start-1,
|
36
|
+
["DS:a:GAUGE:600:U:U",
|
37
|
+
"DS:b:GAUGE:600:U:U",
|
38
|
+
"RRA:AVERAGE:0.5:1:300"])
|
39
|
+
puts "create() returned #{(n.nil?) ? "nil" : n}"
|
40
|
+
puts
|
41
|
+
|
42
|
+
|
43
|
+
# ---------------------------------------------
|
44
|
+
# Update
|
45
|
+
# ---------------------------------------------
|
46
|
+
puts "updating #{rrdname}"
|
47
|
+
val = start.to_i
|
48
|
+
while (val < (start.to_i+300*300)) do
|
49
|
+
rrd.update("a:b", ["#{val}:#{rand()}:#{Math.sin(val / 3000) * 50 + 50}"])
|
50
|
+
val += 300
|
51
|
+
end
|
52
|
+
puts
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
# ---------------------------------------------
|
58
|
+
# Dump
|
59
|
+
# ---------------------------------------------
|
60
|
+
puts "dumping #{rrdname}"
|
61
|
+
n = rrd.dump
|
62
|
+
puts "dump() returned #{(n.nil?) ? "nil" : n}"
|
63
|
+
puts
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
# ---------------------------------------------
|
68
|
+
# Fetch
|
69
|
+
# ---------------------------------------------
|
70
|
+
puts "fetching data from #{rrdname}"
|
71
|
+
arr = rrd.fetch(["AVERAGE"])
|
72
|
+
data = arr[3]
|
73
|
+
puts "got #{data.length} data points"
|
74
|
+
puts
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
# ---------------------------------------------
|
79
|
+
# Info
|
80
|
+
# ---------------------------------------------
|
81
|
+
puts "RRD info "
|
82
|
+
h = rrd.info
|
83
|
+
puts "info() returned #{h.size} items"
|
84
|
+
h.each do |k, v|
|
85
|
+
puts " #{k} --> #{v}"
|
86
|
+
end
|
87
|
+
puts
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
# ---------------------------------------------
|
92
|
+
# Graph
|
93
|
+
# ---------------------------------------------
|
94
|
+
puts "generating graph #{name}.png"
|
95
|
+
rrd.graph(
|
96
|
+
["#{name}.png",
|
97
|
+
"--title", " RubyRRD Demo",
|
98
|
+
"--start", "#{start} + 1 h",
|
99
|
+
"--end", "#{start} + 1000 min",
|
100
|
+
"--interlace",
|
101
|
+
"--imgformat", "PNG",
|
102
|
+
"--width=450",
|
103
|
+
"DEF:a=#{rrd.rrdname}:a:AVERAGE",
|
104
|
+
"DEF:b=#{rrd.rrdname}:b:AVERAGE",
|
105
|
+
"CDEF:line=TIME,2400,%,300,LT,a,UNKN,IF",
|
106
|
+
"AREA:b#00b6e4:beta",
|
107
|
+
"AREA:line#0022e9:alpha",
|
108
|
+
"LINE3:line#ff0000"])
|
109
|
+
puts
|
110
|
+
|
111
|
+
|
112
|
+
exit # <<<<============== STOP ==================
|
113
|
+
|
114
|
+
# ---------------------------------------------
|
115
|
+
# First
|
116
|
+
# ---------------------------------------------
|
117
|
+
puts "first value for #{rrdname}"
|
118
|
+
n = rrd.first(nil)
|
119
|
+
puts "first() returned #{(n.nil?) ? "nil" : n}"
|
120
|
+
n = rrd.first(0)
|
121
|
+
puts "first(0) returned #{(n.nil?) ? "nil" : n}"
|
122
|
+
puts
|
123
|
+
|
124
|
+
# ---------------------------------------------
|
125
|
+
# Last
|
126
|
+
# ---------------------------------------------
|
127
|
+
puts "last value for #{rrdname}"
|
128
|
+
n = rrd.last
|
129
|
+
puts "last() returned #{(n.nil?) ? "nil" : n}"
|
130
|
+
puts
|
131
|
+
|
132
|
+
|
133
|
+
print "This script has created #{name}.png in the current directory\n";
|
134
|
+
print "This demonstrates the use of the TIME and % RPN operators\n";
|
data/examples/minmax.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "RRDtool"
|
4
|
+
|
5
|
+
name = "minmax"
|
6
|
+
rrdname = "#{name}.rrd"
|
7
|
+
start = Time.now.to_i
|
8
|
+
|
9
|
+
rrd = RRDtool.new(rrdname)
|
10
|
+
puts "created new RRD database -> #{rrd.rrdname}"
|
11
|
+
|
12
|
+
puts "vers -> #{RRDtool.version}"
|
13
|
+
|
14
|
+
# ---------------------------------------------
|
15
|
+
# Create
|
16
|
+
# ---------------------------------------------
|
17
|
+
puts " .. creating #{rrdname}"
|
18
|
+
n = rrd.create(
|
19
|
+
300, start-1,
|
20
|
+
["DS:ds_0:GAUGE:600:U:U",
|
21
|
+
"RRA:AVERAGE:0.5:1:300",
|
22
|
+
"RRA:MIN:0.5:12:300",
|
23
|
+
"RRA:MAX:0.5:12:300"])
|
24
|
+
|
25
|
+
# ---------------------------------------------
|
26
|
+
# Update
|
27
|
+
# ---------------------------------------------
|
28
|
+
puts " .. updating #{rrdname}"
|
29
|
+
val = start.to_i
|
30
|
+
while (val < (start.to_i+300*300)) do
|
31
|
+
rrd.update("ds_0", ["#{val}:#{Math.sin(val / 3000) * 50 + 50}"])
|
32
|
+
val += 300
|
33
|
+
# sleep(1)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
# ---------------------------------------------
|
39
|
+
# Graph
|
40
|
+
# ---------------------------------------------
|
41
|
+
puts "generating graph #{name}.png"
|
42
|
+
RRDtool.graph(
|
43
|
+
["#{name}.png",
|
44
|
+
"DEF:a=#{rrdname}:ds_0:AVERAGE",
|
45
|
+
"DEF:b=#{rrdname}:ds_0:MIN",
|
46
|
+
"DEF:c=#{rrdname}:ds_0:MAX",
|
47
|
+
"--title", " #{name} Demo",
|
48
|
+
"--start", "now",
|
49
|
+
"--end", "start+1d",
|
50
|
+
"--lower-limit=0",
|
51
|
+
"--interlace",
|
52
|
+
"--imgformat", "PNG",
|
53
|
+
"--width=450",
|
54
|
+
"AREA:a#00b6e4:real",
|
55
|
+
"LINE1:b#0022e9:min",
|
56
|
+
"LINE1:c#000000:max"])
|
57
|
+
|
58
|
+
|
59
|
+
puts "This script has created #{rrdname}.png in the current directory"
|
60
|
+
puts "This demonstrates the use of the TIME and % RPN operators"
|
data/extconf.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# $Id: extconf.rb,v 1.3 2006/10/17 23:34:06 dbach Exp $
|
2
|
+
# Lost ticket pays maximum rate.
|
3
|
+
|
4
|
+
require 'mkmf'
|
5
|
+
|
6
|
+
# Be sure to say where you rrdtool lives:
|
7
|
+
# ruby ./extconf.rb --with-rrd-dir=/usr/local/rrdtool-1.2.12
|
8
|
+
libpaths=%w(/lib /usr/lib /usr/local/lib)
|
9
|
+
%w(art_lgpl_2 freetype png z).sort.reverse.each do |lib|
|
10
|
+
find_library(lib, nil, *libpaths)
|
11
|
+
end
|
12
|
+
|
13
|
+
dir_config("rrd")
|
14
|
+
# rrd_first is only defined rrdtool >= 1.2.x
|
15
|
+
have_library("rrd", "rrd_first")
|
16
|
+
|
17
|
+
# rrd_dump_r has 2nd arg in rrdtool >= 1.2.14
|
18
|
+
if try_link(<<EOF)
|
19
|
+
#include <rrd.h>
|
20
|
+
main()
|
21
|
+
{
|
22
|
+
rrd_dump_r("/dev/null", NULL);
|
23
|
+
}
|
24
|
+
EOF
|
25
|
+
$CFLAGS += " -DHAVE_RRD_DUMP_R_2"
|
26
|
+
end
|
27
|
+
|
28
|
+
create_makefile("RRDtool")
|
29
|
+
|
data/rrd_addition.h
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
/* -*- C -*-
|
2
|
+
* file: rrd_addition.h
|
3
|
+
* date: $Date: 2005/08/04 01:16:07 $
|
4
|
+
* init: 2005-07-26
|
5
|
+
* vers: $Version$
|
6
|
+
* auth: $Author: probertm $
|
7
|
+
* -----
|
8
|
+
*
|
9
|
+
* Support file to add rrd_info() to rrd.h
|
10
|
+
*
|
11
|
+
*/
|
12
|
+
#ifndef __RRD_ADDITION_H
|
13
|
+
#define __RRD_ADDITION_H
|
14
|
+
|
15
|
+
#if defined(__cplusplus) || defined(c_plusplus)
|
16
|
+
extern "C" {
|
17
|
+
#endif
|
18
|
+
|
19
|
+
/* rrd info interface */
|
20
|
+
enum info_type { RD_I_VAL=0,
|
21
|
+
RD_I_CNT,
|
22
|
+
RD_I_STR,
|
23
|
+
RD_I_INT };
|
24
|
+
|
25
|
+
typedef union infoval {
|
26
|
+
unsigned long u_cnt;
|
27
|
+
rrd_value_t u_val;
|
28
|
+
char *u_str;
|
29
|
+
int u_int;
|
30
|
+
} infoval;
|
31
|
+
|
32
|
+
typedef struct info_t {
|
33
|
+
char *key;
|
34
|
+
enum info_type type;
|
35
|
+
union infoval value;
|
36
|
+
struct info_t *next;
|
37
|
+
} info_t;
|
38
|
+
|
39
|
+
info_t *rrd_info(int, char **);
|
40
|
+
info_t *rrd_info_r(char *);
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
#if defined(__cplusplus) || defined(c_plusplus)
|
45
|
+
}
|
46
|
+
#endif
|
47
|
+
#endif /* __RRD_ADDITION_H */
|
data/rubyrrdtool.c
ADDED
@@ -0,0 +1,1093 @@
|
|
1
|
+
/* -----
|
2
|
+
* file: rubyrrdtool.c
|
3
|
+
* date: $Date: 2006/10/18 21:44:10 $
|
4
|
+
* init: 2005-07-26
|
5
|
+
* vers: $Version$
|
6
|
+
* auth: $Author: dbach $
|
7
|
+
* -----
|
8
|
+
* This is a Ruby extension (binding) for RRDTool
|
9
|
+
*
|
10
|
+
* http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/index.en.html
|
11
|
+
*
|
12
|
+
* It is based on the initial work done by Miles Egan <miles@caddr.com>
|
13
|
+
* and modified by Mark Probert (probert at acm dot org) to bring
|
14
|
+
* support in line with RRDTool 1.2.x
|
15
|
+
*
|
16
|
+
* Released under the MIT Licence
|
17
|
+
*
|
18
|
+
*/
|
19
|
+
|
20
|
+
#include <unistd.h>
|
21
|
+
#include <stdbool.h>
|
22
|
+
#include <math.h> /* for isnan */
|
23
|
+
#include <ruby.h>
|
24
|
+
#include <rrd.h>
|
25
|
+
#include "rrd_addition.h"
|
26
|
+
|
27
|
+
/* printf debugging */
|
28
|
+
#define R_RRD_DEBUG_OFF 0 /* no debugging */
|
29
|
+
#define R_RRD_DEBUG_SIM 1 /* basic debug */
|
30
|
+
#define R_RRD_DEBUG_DET 2 /* more details */
|
31
|
+
#undef R_RRD_DBG
|
32
|
+
|
33
|
+
#ifdef R_RRD_DBG
|
34
|
+
void _dbug(int level, char *s) {
|
35
|
+
if (level <= R_RRD_DBG) {
|
36
|
+
printf(" --> %s\n", s);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
#endif
|
40
|
+
|
41
|
+
VALUE cRRDtool; /* class */
|
42
|
+
VALUE rb_eRRDtoolError;
|
43
|
+
|
44
|
+
extern int optind;
|
45
|
+
extern int opterr;
|
46
|
+
|
47
|
+
typedef int (*RRDtoolFUNC)(int argc, char ** argv);
|
48
|
+
|
49
|
+
/*
|
50
|
+
* define macros for easy error checking
|
51
|
+
*/
|
52
|
+
|
53
|
+
#define RRD_RAISE rb_raise(rb_eRRDtoolError, rrd_get_error());
|
54
|
+
|
55
|
+
#define RRD_CHECK_ERROR if (rrd_test_error()) RRD_RAISE
|
56
|
+
|
57
|
+
#define NUM_BUF_SZ 80
|
58
|
+
|
59
|
+
/*
|
60
|
+
* Define a structure to store counted array of strings
|
61
|
+
*/
|
62
|
+
typedef struct string_array_t {
|
63
|
+
int len;
|
64
|
+
char **strs;
|
65
|
+
} s_arr;
|
66
|
+
|
67
|
+
/*
|
68
|
+
* Create a new array of strings based on a Ruby array.
|
69
|
+
*
|
70
|
+
* If name_f value is TRUE, then we need to put the
|
71
|
+
* rrdname value as the first element of the array.
|
72
|
+
*
|
73
|
+
* If dummy_f is true, then add "dummy" at index 0.
|
74
|
+
* I have no idea why we do this, but it seems to be
|
75
|
+
* needed for some reason.
|
76
|
+
*
|
77
|
+
*/
|
78
|
+
static s_arr s_arr_new(VALUE self, bool name_f, bool dummy_f, VALUE strs)
|
79
|
+
{
|
80
|
+
s_arr a;
|
81
|
+
int i, j; /* index counters */
|
82
|
+
VALUE rrd; /* name of the RRD we are dealing with */
|
83
|
+
|
84
|
+
#ifdef R_RRD_DBG
|
85
|
+
char buf[NUM_BUF_SZ+1];
|
86
|
+
#endif
|
87
|
+
|
88
|
+
#ifdef R_RRD_DBG
|
89
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr: name_f=[%d] dummy_f=[%d]", name_f, dummy_f);
|
90
|
+
buf[NUM_BUF_SZ] = 0;
|
91
|
+
_dbug(R_RRD_DEBUG_DET, buf);
|
92
|
+
#endif
|
93
|
+
|
94
|
+
rrd = rb_iv_get(self, "@rrdname");
|
95
|
+
Check_Type(strs, T_ARRAY);
|
96
|
+
|
97
|
+
/* set the array length */
|
98
|
+
a.len = RARRAY(strs)->len;
|
99
|
+
if (name_f) { a.len++; }
|
100
|
+
if (dummy_f) { a.len++; }
|
101
|
+
a.strs = ALLOC_N(char*, a.len);
|
102
|
+
|
103
|
+
#ifdef R_RRD_DBG
|
104
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr: array length set to %d", a.len);
|
105
|
+
buf[NUM_BUF_SZ] = 0;
|
106
|
+
_dbug(R_RRD_DEBUG_DET, buf);
|
107
|
+
#endif
|
108
|
+
|
109
|
+
i = 0;
|
110
|
+
/* drb: some of the rrd API functions assume the action preceeds the
|
111
|
+
* command arguments */
|
112
|
+
if (dummy_f) {
|
113
|
+
a.strs[i] = strdup("dummy");
|
114
|
+
i++;
|
115
|
+
}
|
116
|
+
|
117
|
+
/* add the rrdname if needed */
|
118
|
+
if (name_f) {
|
119
|
+
a.strs[i] = strdup(STR2CSTR(rrd));
|
120
|
+
i++;
|
121
|
+
}
|
122
|
+
|
123
|
+
/* now add the strings */
|
124
|
+
j = 0;
|
125
|
+
while (i < a.len) {
|
126
|
+
VALUE v = rb_ary_entry(strs, j);
|
127
|
+
|
128
|
+
switch (TYPE(v)) {
|
129
|
+
case T_BIGNUM:
|
130
|
+
case T_FIXNUM:
|
131
|
+
v = rb_obj_as_string(v);
|
132
|
+
/* FALLTHROUGH */
|
133
|
+
case T_STRING:
|
134
|
+
a.strs[i] = strdup(StringValuePtr(v));
|
135
|
+
#ifdef R_RRD_DBG
|
136
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr: adding: i=%d val=%s", i, a.strs[i]);
|
137
|
+
buf[NUM_BUF_SZ] = 0;
|
138
|
+
_dbug(R_RRD_DEBUG_DET, buf);
|
139
|
+
#endif
|
140
|
+
break;
|
141
|
+
|
142
|
+
default:
|
143
|
+
#ifdef R_RRD_DBG
|
144
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr: adding: i=%d type=%d", i, TYPE(v));
|
145
|
+
buf[NUM_BUF_SZ] = 0;
|
146
|
+
_dbug(R_RRD_DEBUG_DET, buf);
|
147
|
+
#endif
|
148
|
+
rb_raise(rb_eTypeError, "invalid argument for string array");
|
149
|
+
break;
|
150
|
+
}
|
151
|
+
i++; j++;
|
152
|
+
}
|
153
|
+
|
154
|
+
#ifdef R_RRD_DBG
|
155
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr: len -> %d", a.len);
|
156
|
+
buf[NUM_BUF_SZ] = 0;
|
157
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
158
|
+
for (i = 0; i < a.len; i++) {
|
159
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr[%d] -> %s", i, a.strs[i]);
|
160
|
+
buf[NUM_BUF_SZ] = 0;
|
161
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
162
|
+
}
|
163
|
+
#endif
|
164
|
+
return a;
|
165
|
+
}
|
166
|
+
|
167
|
+
|
168
|
+
/*
|
169
|
+
* clean up the string array
|
170
|
+
*/
|
171
|
+
static void s_arr_del(s_arr a)
|
172
|
+
{
|
173
|
+
int i;
|
174
|
+
for (i = 0; i < a.len; i++) {
|
175
|
+
free(a.strs[i]);
|
176
|
+
}
|
177
|
+
free(a.strs);
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
/*
|
182
|
+
* add an element to a string array at the start of the array
|
183
|
+
*/
|
184
|
+
static bool s_arr_push(char *val, s_arr *sa) {
|
185
|
+
char **tmp;
|
186
|
+
int i;
|
187
|
+
#ifdef R_RRD_DBG
|
188
|
+
char buf[NUM_BUF_SZ+1];
|
189
|
+
#endif
|
190
|
+
|
191
|
+
#ifdef R_RRD_DBG
|
192
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr_push: n=%d val=%s", sa->len, val);
|
193
|
+
buf[NUM_BUF_SZ] = 0;
|
194
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
195
|
+
#endif
|
196
|
+
|
197
|
+
/* set the array length */
|
198
|
+
sa->len += 1;
|
199
|
+
tmp = ALLOC_N(char*, sa->len);
|
200
|
+
|
201
|
+
i = 0;
|
202
|
+
tmp[i++] = strdup(val);
|
203
|
+
while(i <= sa->len) {
|
204
|
+
if (sa->strs[i-1] != NULL) {
|
205
|
+
tmp[i] = strdup(sa->strs[i-1]);
|
206
|
+
free(sa->strs[i-1]);
|
207
|
+
}
|
208
|
+
i++;
|
209
|
+
}
|
210
|
+
sa->strs = tmp;
|
211
|
+
|
212
|
+
#ifdef R_RRD_DBG
|
213
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr_push: len -> %d", sa->len);
|
214
|
+
buf[NUM_BUF_SZ] = 0;
|
215
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
216
|
+
for (i = 0; i < sa->len; i++) {
|
217
|
+
snprintf(buf, NUM_BUF_SZ, "s_arr_add: s_arr[%d] -> %s", i, sa->strs[i]);
|
218
|
+
buf[NUM_BUF_SZ] = 0;
|
219
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
220
|
+
}
|
221
|
+
#endif
|
222
|
+
return true;
|
223
|
+
}
|
224
|
+
|
225
|
+
|
226
|
+
/*
|
227
|
+
* reset the internal state
|
228
|
+
*/
|
229
|
+
static void reset_rrd_state()
|
230
|
+
{
|
231
|
+
optind = 0;
|
232
|
+
opterr = 0;
|
233
|
+
rrd_clear_error();
|
234
|
+
}
|
235
|
+
|
236
|
+
|
237
|
+
/*
|
238
|
+
* Document-method: create
|
239
|
+
*
|
240
|
+
* call-seq:
|
241
|
+
* rrd.create(pdp_step, last_up, arg_array) -> [Qnil|Qtrue]
|
242
|
+
*
|
243
|
+
* The create function of RRDtool lets you set up new Round Robin
|
244
|
+
* Database (RRD) files. The file is created at its final, full size
|
245
|
+
* and filled with *UNKNOWN* data.
|
246
|
+
*
|
247
|
+
* create filename [--start|-b start time] [--step|-s step]
|
248
|
+
* [DS:ds-name:DST:heartbeat:min:max] [RRA:CF:xff:steps:rows]
|
249
|
+
*
|
250
|
+
*
|
251
|
+
* filename
|
252
|
+
* The name of the RRD you want to create. RRD files should end with
|
253
|
+
* the extension .rrd. However, RRDtool will accept any filename.
|
254
|
+
*
|
255
|
+
* pdp_step (default: 300 seconds)
|
256
|
+
* Specifies the base interval in seconds with which data will be
|
257
|
+
* fed into the RRD.
|
258
|
+
*
|
259
|
+
* last_up start time (default: now - 10s)
|
260
|
+
* Specifies the time in seconds since 1970-01-01 UTC when the first
|
261
|
+
* value should be added to the RRD. RRDtool will not accept any data
|
262
|
+
* timed before or at the time specified.
|
263
|
+
*
|
264
|
+
* DS:ds-name:DST:dst arguments
|
265
|
+
* A single RRD can accept input from several data sources (DS), for
|
266
|
+
* example incoming and outgoing traffic on a specific communication line.
|
267
|
+
* With the DS configuration option you must define some basic properties
|
268
|
+
* of each data source you want to store in the RRD.
|
269
|
+
*
|
270
|
+
* ds-name is the name you will use to reference this particular data
|
271
|
+
* source from an RRD. A ds-name must be 1 to 19 characters long in
|
272
|
+
* the characters [a-zA-Z0-9_].
|
273
|
+
*
|
274
|
+
* DST defines the Data Source Type. The remaining arguments of a data
|
275
|
+
* source entry depend on the data source type. For GAUGE, COUNTER, DERIVE,
|
276
|
+
* and ABSOLUTE the format for a data source entry is:
|
277
|
+
*
|
278
|
+
* DS:ds-name:GAUGE | COUNTER | DERIVE | ABSOLUTE:heartbeat:min:max
|
279
|
+
*
|
280
|
+
* For COMPUTE data sources, the format is:
|
281
|
+
*
|
282
|
+
* DS:ds-name:COMPUTE:rpn-expression
|
283
|
+
*
|
284
|
+
* NB: we use the thread-safe version of the command rrd_create_r()
|
285
|
+
*/
|
286
|
+
VALUE rrdtool_create(VALUE self, VALUE ostep, VALUE update, VALUE args)
|
287
|
+
{
|
288
|
+
s_arr a; /* varargs in the form of a string array */
|
289
|
+
VALUE rval; /* our result */
|
290
|
+
VALUE rrd; /* name of the RRD file to create */
|
291
|
+
unsigned long pdp_step; /* the stepping time interval */
|
292
|
+
time_t last_up; /* last update time */
|
293
|
+
#ifdef R_RRD_DBG
|
294
|
+
char buf[NUM_BUF_SZ+1];
|
295
|
+
#endif
|
296
|
+
int result;
|
297
|
+
|
298
|
+
reset_rrd_state();
|
299
|
+
|
300
|
+
rrd = rb_iv_get(self, "@rrdname");
|
301
|
+
|
302
|
+
/* conversion ... */
|
303
|
+
pdp_step = NUM2LONG(ostep);
|
304
|
+
last_up = (time_t)NUM2LONG(update);
|
305
|
+
#ifdef R_RRD_DBG
|
306
|
+
snprintf(buf, NUM_BUF_SZ, "n=[%s] : step=%lu : up=%ld", STR2CSTR(rrd),
|
307
|
+
pdp_step, (long int)last_up);
|
308
|
+
buf[NUM_BUF_SZ] = 0;
|
309
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
310
|
+
#endif
|
311
|
+
a = s_arr_new(self, false, false, args);
|
312
|
+
#ifdef R_RRD_DBG
|
313
|
+
_dbug(R_RRD_DEBUG_SIM, "call");
|
314
|
+
#endif
|
315
|
+
|
316
|
+
/* now run the command */
|
317
|
+
result = rrd_create_r(STR2CSTR(rrd), pdp_step, last_up, a.len, a.strs);
|
318
|
+
|
319
|
+
#ifdef R_RRD_DBG
|
320
|
+
_dbug(R_RRD_DEBUG_SIM, "cleanup");
|
321
|
+
#endif
|
322
|
+
s_arr_del(a);
|
323
|
+
|
324
|
+
if (result == -1) {
|
325
|
+
RRD_RAISE;
|
326
|
+
rval = Qnil;
|
327
|
+
} else {
|
328
|
+
rval = Qtrue;
|
329
|
+
}
|
330
|
+
return rval;
|
331
|
+
}
|
332
|
+
|
333
|
+
|
334
|
+
/*
|
335
|
+
* Document-method: dump
|
336
|
+
*
|
337
|
+
* call-seq:
|
338
|
+
* rrd.dump -> [Qnil|Qtrue]
|
339
|
+
*
|
340
|
+
* The dump function prints the contents of an RRD in human readable (?)
|
341
|
+
* XML format. This format can be read by rrd_restore. Together they allow
|
342
|
+
* you to transfer your files from one computer architecture to another
|
343
|
+
* as well to manipulate the contents of an RRD file in a somewhat more
|
344
|
+
* convenient manner.
|
345
|
+
*
|
346
|
+
* This routine uses th thread-safe version rrd_dump_r()
|
347
|
+
*
|
348
|
+
* Note: This routine is a bit of a mess from a scripting persepective.
|
349
|
+
* rrd_dump_r() doesn't take a filename for the output, it just
|
350
|
+
* spits the XML to stdout. Redirection from with an extension
|
351
|
+
* seems to be hard. So, for the moment, we just rely on the
|
352
|
+
* default behaviour and send in a change request for the fn.
|
353
|
+
*
|
354
|
+
* For the version that takes
|
355
|
+
*
|
356
|
+
*
|
357
|
+
*/
|
358
|
+
#ifdef HAVE_RRD_DUMP_R_2
|
359
|
+
VALUE rrdtool_dump(VALUE self, VALUE output)
|
360
|
+
{
|
361
|
+
int ret; /* result of rrd_dump_r */
|
362
|
+
VALUE rval; /* our result */
|
363
|
+
VALUE rrd; /* rrd database filename */
|
364
|
+
|
365
|
+
reset_rrd_state();
|
366
|
+
|
367
|
+
rrd = rb_iv_get(self, "@rrdname");
|
368
|
+
|
369
|
+
/* type checking */
|
370
|
+
Check_Type(output, T_STRING);
|
371
|
+
|
372
|
+
ret = rrd_dump_r(STR2CSTR(rrd), STR2CSTR(output));
|
373
|
+
if (ret == -1) {
|
374
|
+
RRD_RAISE;
|
375
|
+
rval = Qnil;
|
376
|
+
} else {
|
377
|
+
rval = Qtrue;
|
378
|
+
}
|
379
|
+
return rval;
|
380
|
+
}
|
381
|
+
#endif
|
382
|
+
|
383
|
+
/*
|
384
|
+
* Document-method: first
|
385
|
+
*
|
386
|
+
* call-seq:
|
387
|
+
* rrd.first(rra_idx) -> [Qnil|BIGNUM(time)]
|
388
|
+
*
|
389
|
+
* The first function returns the UNIX timestamp of the first data sample
|
390
|
+
* entered into the specified RRA of the RRD file.
|
391
|
+
*
|
392
|
+
* The index number of the RRA that is to be examined. If not specified,
|
393
|
+
* the index defaults to zero. RRA index numbers can be determined through
|
394
|
+
* rrdtool info.
|
395
|
+
*
|
396
|
+
* NB: this function uses the thread-safe version rrd_first_r()
|
397
|
+
*
|
398
|
+
*/
|
399
|
+
VALUE rrdtool_first(VALUE self, VALUE orra_idx)
|
400
|
+
{
|
401
|
+
VALUE rval; /* our result */
|
402
|
+
VALUE rrd; /* rrd database filename */
|
403
|
+
int idx; /* index in integer form */
|
404
|
+
time_t when; /* the found value */
|
405
|
+
#ifdef R_RRD_DBG
|
406
|
+
char buf[NUM_BUF_SZ+1];
|
407
|
+
#endif
|
408
|
+
|
409
|
+
reset_rrd_state();
|
410
|
+
|
411
|
+
rrd = rb_iv_get(self, "@rrdname");
|
412
|
+
if (orra_idx == Qnil) { idx = 0; }
|
413
|
+
else {
|
414
|
+
idx = NUM2INT(orra_idx);
|
415
|
+
}
|
416
|
+
|
417
|
+
when = rrd_first_r(STR2CSTR(rrd), idx);
|
418
|
+
if (when == -1) {
|
419
|
+
RRD_RAISE;
|
420
|
+
rval = Qnil;
|
421
|
+
} else {
|
422
|
+
rval = LONG2NUM(when);
|
423
|
+
}
|
424
|
+
|
425
|
+
#ifdef R_RRD_DBG
|
426
|
+
snprintf(buf, NUM_BUF_SZ, "first: rrd=[%s] : idx=%d : val=%ld",
|
427
|
+
STR2CSTR(rrd), idx, when);
|
428
|
+
buf[NUM_BUF_SZ] = 0;
|
429
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
430
|
+
#endif
|
431
|
+
return rval;
|
432
|
+
}
|
433
|
+
|
434
|
+
|
435
|
+
/*
|
436
|
+
* Document-method: last
|
437
|
+
*
|
438
|
+
* call-seq:
|
439
|
+
* rrd.last -> [Qnil|BIGNUM(time)]
|
440
|
+
*
|
441
|
+
* The last function returns the UNIX timestamp of the most recent
|
442
|
+
* update of the RRD.
|
443
|
+
*
|
444
|
+
* NB: this function uses the thread-safe version rrd_lasst_r()
|
445
|
+
*
|
446
|
+
*/
|
447
|
+
VALUE rrdtool_last(VALUE self)
|
448
|
+
{
|
449
|
+
VALUE rval; /* our result */
|
450
|
+
VALUE rrd; /* rrd database filename */
|
451
|
+
time_t when; /* the found value */
|
452
|
+
#ifdef R_RRD_DBG
|
453
|
+
char buf[NUM_BUF_SZ+1];
|
454
|
+
#endif
|
455
|
+
|
456
|
+
reset_rrd_state();
|
457
|
+
|
458
|
+
rrd = rb_iv_get(self, "@rrdname");
|
459
|
+
|
460
|
+
when = rrd_last_r(STR2CSTR(rrd));
|
461
|
+
if (when == -1) {
|
462
|
+
RRD_RAISE;
|
463
|
+
rval = Qnil;
|
464
|
+
} else {
|
465
|
+
rval = LONG2NUM(when);
|
466
|
+
}
|
467
|
+
|
468
|
+
#ifdef R_RRD_DBG
|
469
|
+
snprintf(buf, NUM_BUF_SZ, "last: rrd=[%s] : val=%ld", STR2CSTR(rrd), when);
|
470
|
+
buf[NUM_BUF_SZ] = 0;
|
471
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
472
|
+
#endif
|
473
|
+
return rval;
|
474
|
+
}
|
475
|
+
|
476
|
+
|
477
|
+
/*
|
478
|
+
* Document-method: version
|
479
|
+
*
|
480
|
+
* call-seq:
|
481
|
+
* rrd.version -> [Qnil|FLOAT(version_number)]
|
482
|
+
*
|
483
|
+
* Returns the version number of the RRDtool library
|
484
|
+
*
|
485
|
+
*/
|
486
|
+
VALUE rrdtool_version(VALUE self)
|
487
|
+
{
|
488
|
+
VALUE rval; /* our result */
|
489
|
+
double vers; /* version number */
|
490
|
+
#ifdef R_RRD_DBG
|
491
|
+
char buf[NUM_BUF_SZ+1];
|
492
|
+
#endif
|
493
|
+
|
494
|
+
reset_rrd_state();
|
495
|
+
|
496
|
+
vers = rrd_version();
|
497
|
+
rval = rb_float_new(vers);
|
498
|
+
|
499
|
+
#ifdef R_RRD_DBG
|
500
|
+
snprintf(buf, NUM_BUF_SZ, "version: val=%f", vers);
|
501
|
+
buf[NUM_BUF_SZ] = 0;
|
502
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
503
|
+
#endif
|
504
|
+
return rval;
|
505
|
+
}
|
506
|
+
|
507
|
+
|
508
|
+
|
509
|
+
/*
|
510
|
+
* Document-method: update
|
511
|
+
*
|
512
|
+
* call-seq:
|
513
|
+
* rrd.update(template, arg_array) -> [Qnil|Qtrue]
|
514
|
+
*
|
515
|
+
* The update function feeds new data values into an RRD. The data is time aligned
|
516
|
+
* (interpolated) according to the properties of the RRD to which the data is written.
|
517
|
+
*
|
518
|
+
*
|
519
|
+
* filename
|
520
|
+
* The name of the RRD you want to update.
|
521
|
+
*
|
522
|
+
* template
|
523
|
+
* By default, the update function expects its data input in the order
|
524
|
+
* the data sources are defined in the RRD, excluding any COMPUTE data
|
525
|
+
* sources (i.e. if the third data source DST is COMPUTE, the third input
|
526
|
+
* value will be mapped to the fourth data source in the RRD and so on).
|
527
|
+
* This is not very error resistant, as you might be sending the wrong
|
528
|
+
* data into an RRD.
|
529
|
+
*
|
530
|
+
* The template switch allows you to specify which data sources you are
|
531
|
+
* going to update and in which order. If the data sources specified in
|
532
|
+
* the template are not available in the RRD file, the update process
|
533
|
+
* will abort with an error message.
|
534
|
+
*
|
535
|
+
* While it appears possible with the template switch to update data sources
|
536
|
+
* asynchronously, RRDtool implicitly assigns non-COMPUTE data sources missing
|
537
|
+
* from the template the *UNKNOWN* value.
|
538
|
+
*
|
539
|
+
* Do not specify a value for a COMPUTE DST in the update function. If this
|
540
|
+
* is done accidentally (and this can only be done using the template switch),
|
541
|
+
* RRDtool will ignore the value specified for the COMPUTE DST.
|
542
|
+
*
|
543
|
+
* N|timestamp:value[:value...]
|
544
|
+
* The data used for updating the RRD was acquired at a certain time. This time
|
545
|
+
* can either be defined in seconds since 1970-01-01 or by using the letter 'N',
|
546
|
+
* in which case the update time is set to be the current time. Negative time
|
547
|
+
* values are subtracted from the current time. An AT_STYLE TIME SPECIFICATION
|
548
|
+
* MUST NOT be used.
|
549
|
+
*
|
550
|
+
* The remaining elements of the argument are DS updates. The order of this
|
551
|
+
* list is the same as the order the data sources were defined in the RRA. If
|
552
|
+
* there is no data for a certain data-source, the letter U (e.g., N:0.1:U:1)
|
553
|
+
* can be specified.
|
554
|
+
*
|
555
|
+
* The format of the value acquired from the data source is dependent on the
|
556
|
+
* data source type chosen. Normally it will be numeric, but the data acquisition
|
557
|
+
* modules may impose their very own parsing of this parameter as long as the
|
558
|
+
* colon (:) remains the data source value separator.
|
559
|
+
*
|
560
|
+
* NB: This function uses the thread-safe rrd_update_r() version of the call.
|
561
|
+
*
|
562
|
+
*/
|
563
|
+
VALUE rrdtool_update(VALUE self, VALUE otemp, VALUE args)
|
564
|
+
{
|
565
|
+
s_arr a; /* varargs in the form of a string array */
|
566
|
+
VALUE rval; /* our result */
|
567
|
+
VALUE rrd; /* name of the RRD file to create */
|
568
|
+
VALUE tmpl; /* DS template */
|
569
|
+
#ifdef R_RRD_DBG
|
570
|
+
char buf[NUM_BUF_SZ+1];
|
571
|
+
#endif
|
572
|
+
int result;
|
573
|
+
|
574
|
+
reset_rrd_state();
|
575
|
+
|
576
|
+
rrd = rb_iv_get(self, "@rrdname");
|
577
|
+
|
578
|
+
/* initial type checking */
|
579
|
+
Check_Type(otemp, T_STRING);
|
580
|
+
tmpl = StringValue(otemp);
|
581
|
+
|
582
|
+
#ifdef R_RRD_DBG
|
583
|
+
snprintf(buf, NUM_BUF_SZ, "n=[%s] : tmpl=%s", STR2CSTR(rrd), STR2CSTR(tmpl));
|
584
|
+
buf[NUM_BUF_SZ] = 0;
|
585
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
586
|
+
#endif
|
587
|
+
a = s_arr_new(self, false, false, args);
|
588
|
+
|
589
|
+
/* now run the command */
|
590
|
+
result = rrd_update_r(STR2CSTR(rrd), STR2CSTR(tmpl), a.len, a.strs);
|
591
|
+
/* cleanup */
|
592
|
+
s_arr_del(a);
|
593
|
+
|
594
|
+
if (result == -1) {
|
595
|
+
RRD_RAISE;
|
596
|
+
rval = Qnil;
|
597
|
+
} else {
|
598
|
+
rval = Qtrue;
|
599
|
+
}
|
600
|
+
return rval;
|
601
|
+
}
|
602
|
+
|
603
|
+
|
604
|
+
|
605
|
+
/*
|
606
|
+
* default calling mechanism for those functions that take
|
607
|
+
* the old style argc, argv paramters with rrdtool_name as
|
608
|
+
* the first paramater
|
609
|
+
*/
|
610
|
+
VALUE rrdtool_call(VALUE self, RRDtoolFUNC fn, VALUE args)
|
611
|
+
{
|
612
|
+
s_arr a; /* varargs in the form of a string array */
|
613
|
+
VALUE rval; /* our result */
|
614
|
+
int result;
|
615
|
+
|
616
|
+
reset_rrd_state();
|
617
|
+
|
618
|
+
a = s_arr_new(self, true, false, args);
|
619
|
+
|
620
|
+
/* now run the command */
|
621
|
+
result = fn(a.len, a.strs);
|
622
|
+
|
623
|
+
/* cleanup */
|
624
|
+
s_arr_del(a);
|
625
|
+
|
626
|
+
if (result == -1) {
|
627
|
+
RRD_RAISE;
|
628
|
+
rval = Qnil;
|
629
|
+
} else {
|
630
|
+
rval = Qtrue;
|
631
|
+
}
|
632
|
+
return rval;
|
633
|
+
}
|
634
|
+
|
635
|
+
|
636
|
+
/*
|
637
|
+
* Document-method: tune
|
638
|
+
*
|
639
|
+
* call-seq:
|
640
|
+
* rrd.tune(varargs) -> [Qnil|Qtrue]
|
641
|
+
*
|
642
|
+
* The tune option allows you to alter some of the basic configuration
|
643
|
+
* values stored in the header area of a Round Robin Database (RRD).
|
644
|
+
*
|
645
|
+
* One application of the tune function is to relax the validation rules
|
646
|
+
* on an RRD. This allows to fill a new RRD with data available in larger
|
647
|
+
* intervals than what you would normally want to permit. Be very careful
|
648
|
+
* with tune operations for COMPUTE data sources. Setting the min, max,
|
649
|
+
* and heartbeat for a COMPUTE data source without changing the data source
|
650
|
+
* type to a non-COMPUTE DST WILL corrupt the data source header in the RRD.
|
651
|
+
*
|
652
|
+
* A second application of the tune function is to set or alter parameters
|
653
|
+
* used by the specialized function RRAs for aberrant behavior detection.
|
654
|
+
*
|
655
|
+
*/
|
656
|
+
VALUE rrdtool_tune(VALUE self, VALUE args)
|
657
|
+
{
|
658
|
+
return rrdtool_call(self, rrd_tune, args);
|
659
|
+
}
|
660
|
+
|
661
|
+
/*
|
662
|
+
* Document-method: resize
|
663
|
+
*
|
664
|
+
* call-seq:
|
665
|
+
* rrd.resize(varargs) -> [Qnil|Qtrue]
|
666
|
+
*
|
667
|
+
* The resize function is used to modify the number of rows in an RRA.
|
668
|
+
*
|
669
|
+
* rra-num
|
670
|
+
* the RRA you want to alter.
|
671
|
+
*
|
672
|
+
* GROW
|
673
|
+
* used if you want to add extra rows to an RRA. The extra rows will be
|
674
|
+
* inserted as the rows that are oldest.
|
675
|
+
*
|
676
|
+
* SHRINK
|
677
|
+
* used if you want to remove rows from an RRA. The rows that will be
|
678
|
+
* removed are the oldest rows.
|
679
|
+
*
|
680
|
+
* rows
|
681
|
+
* the number of rows you want to add or remove.
|
682
|
+
*
|
683
|
+
*/
|
684
|
+
VALUE rrdtool_resize(VALUE self, VALUE args)
|
685
|
+
{
|
686
|
+
return rrdtool_call(self, rrd_resize, args);
|
687
|
+
}
|
688
|
+
|
689
|
+
|
690
|
+
/*
|
691
|
+
* Document-method: restore
|
692
|
+
*
|
693
|
+
* call-seq:
|
694
|
+
* rrd.restore(varargs) -> [Qnil|Qtrue]
|
695
|
+
*
|
696
|
+
*
|
697
|
+
*/
|
698
|
+
VALUE rrdtool_restore(VALUE self, VALUE oxml, VALUE orrd, VALUE args)
|
699
|
+
{
|
700
|
+
s_arr a; /* varargs in the form of a string array */
|
701
|
+
VALUE rval; /* our result */
|
702
|
+
VALUE rrd; /* name of the RRD file to create */
|
703
|
+
VALUE xml; /* XML template */
|
704
|
+
#ifdef R_RRD_DBG
|
705
|
+
char buf[NUM_BUF_SZ+1];
|
706
|
+
#endif
|
707
|
+
int result;
|
708
|
+
|
709
|
+
reset_rrd_state();
|
710
|
+
|
711
|
+
rrd = rb_iv_get(self, "@rrdname");
|
712
|
+
|
713
|
+
/* initial type checking */
|
714
|
+
Check_Type(oxml, T_STRING);
|
715
|
+
xml = StringValue(oxml);
|
716
|
+
Check_Type(orrd, T_STRING);
|
717
|
+
rrd = StringValue(orrd);
|
718
|
+
|
719
|
+
#ifdef R_RRD_DBG
|
720
|
+
snprintf(buf, NUM_BUF_SZ, "restore: xml=%s rrd=%s",
|
721
|
+
STR2CSTR(xml), STR2CSTR(rrd));
|
722
|
+
buf[NUM_BUF_SZ] = 0;
|
723
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
724
|
+
#endif
|
725
|
+
a = s_arr_new(self, false, false, args);
|
726
|
+
s_arr_push(STR2CSTR(rrd), &a);
|
727
|
+
s_arr_push(STR2CSTR(xml), &a);
|
728
|
+
s_arr_push(STR2CSTR(xml), &a);
|
729
|
+
|
730
|
+
/* now run the command */
|
731
|
+
result = rrd_restore(a.len, a.strs);
|
732
|
+
|
733
|
+
/* cleanup */
|
734
|
+
s_arr_del(a);
|
735
|
+
|
736
|
+
if (result == -1) {
|
737
|
+
RRD_RAISE;
|
738
|
+
rval = Qnil;
|
739
|
+
} else {
|
740
|
+
rval = Qtrue;
|
741
|
+
}
|
742
|
+
return rval;
|
743
|
+
}
|
744
|
+
|
745
|
+
|
746
|
+
/*
|
747
|
+
* Document-method: fetch
|
748
|
+
*
|
749
|
+
* call-seq:
|
750
|
+
* rrd.fetch(str_array) -> (start, end, names, data)
|
751
|
+
*
|
752
|
+
* The fetch function is normally used internally by the graph function to
|
753
|
+
* get data from RRDs. fetch will analyze the RRD and try to retrieve the
|
754
|
+
* data in the resolution requested. The data fetched is printed to stdout.
|
755
|
+
* *UNKNOWN* data is often represented by the string ``NaN'' depending on
|
756
|
+
* your OS's printf function.
|
757
|
+
*
|
758
|
+
* Other call options:
|
759
|
+
*
|
760
|
+
* --resolution|-r resolution (default is the highest resolution)
|
761
|
+
* the interval you want the values to have (seconds per value).
|
762
|
+
* rrdfetch will try to match your request, but it will return data
|
763
|
+
* even if no absolute match is possible.
|
764
|
+
*
|
765
|
+
* --start|-s start (default end-1day)
|
766
|
+
* start of the time series. A time in seconds since epoch (1970-01-01)
|
767
|
+
* is required. Negative numbers are relative to the current time. By
|
768
|
+
* default, one day worth of data will be fetched.
|
769
|
+
*
|
770
|
+
* --end|-e end (default now)
|
771
|
+
* the end of the time series in seconds since epoch.
|
772
|
+
*
|
773
|
+
*/
|
774
|
+
VALUE rrdtool_fetch(VALUE self, VALUE args)
|
775
|
+
{
|
776
|
+
s_arr a;
|
777
|
+
unsigned long i, j, k, step, ds_cnt;
|
778
|
+
rrd_value_t *rrd_data;
|
779
|
+
char **ds_names;
|
780
|
+
VALUE data, names, rval = Qnil;
|
781
|
+
time_t start, end;
|
782
|
+
#ifdef R_RRD_DBG
|
783
|
+
char buf[NUM_BUF_SZ+1];
|
784
|
+
#endif
|
785
|
+
|
786
|
+
reset_rrd_state();
|
787
|
+
|
788
|
+
a = s_arr_new(self, true, true, args);
|
789
|
+
|
790
|
+
rrd_fetch(a.len, a.strs, &start, &end, &step,
|
791
|
+
&ds_cnt, &ds_names, &rrd_data);
|
792
|
+
|
793
|
+
s_arr_del(a);
|
794
|
+
|
795
|
+
RRD_CHECK_ERROR;
|
796
|
+
|
797
|
+
/* process the data .. get the names first */
|
798
|
+
names = rb_ary_new();
|
799
|
+
for (i = 0; i < ds_cnt; i++) {
|
800
|
+
rb_ary_push(names, rb_str_new2(ds_names[i]));
|
801
|
+
#ifdef R_RRD_DBG
|
802
|
+
snprintf(buf, NUM_BUF_SZ, "fetch: names: n=[%s]", ds_names[i]);
|
803
|
+
buf[NUM_BUF_SZ] = 0;
|
804
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
805
|
+
#endif
|
806
|
+
free(ds_names[i]);
|
807
|
+
}
|
808
|
+
free(ds_names);
|
809
|
+
|
810
|
+
/* step over the 2d array containing the data */
|
811
|
+
k = 0;
|
812
|
+
data = rb_ary_new();
|
813
|
+
for (i = start; i <= end; i += step) {
|
814
|
+
VALUE line = rb_ary_new2(ds_cnt);
|
815
|
+
for (j = 0; j < ds_cnt; j++) {
|
816
|
+
rb_ary_store(line, j, rb_float_new(rrd_data[k]));
|
817
|
+
k++;
|
818
|
+
}
|
819
|
+
rb_ary_push(data, line);
|
820
|
+
}
|
821
|
+
free(rrd_data);
|
822
|
+
|
823
|
+
/* now prepare an array for ruby to chew on .. */
|
824
|
+
rval = rb_ary_new2(4);
|
825
|
+
rb_ary_store(rval, 0, LONG2NUM(start));
|
826
|
+
rb_ary_store(rval, 1, LONG2NUM(end));
|
827
|
+
rb_ary_store(rval, 2, names);
|
828
|
+
rb_ary_store(rval, 3, data);
|
829
|
+
|
830
|
+
return rval;
|
831
|
+
}
|
832
|
+
|
833
|
+
|
834
|
+
|
835
|
+
/*
|
836
|
+
* Document-method: xport
|
837
|
+
*
|
838
|
+
* call-seq:
|
839
|
+
* RRDtool.xport(str_array) -> (start, end, step, col_cnt, legend, data)
|
840
|
+
*
|
841
|
+
* The xport function's main purpose is to write an XML formatted
|
842
|
+
* representation of the data stored in one or several RRDs. It can
|
843
|
+
* also extract numerical reports.
|
844
|
+
*
|
845
|
+
* If no XPORT statements are found, there will be no output.
|
846
|
+
*
|
847
|
+
* -s|--start seconds (default end-1day)
|
848
|
+
* The time when the exported range should begin. Time in
|
849
|
+
* seconds since epoch (1970-01-01) is required. Negative
|
850
|
+
* numbers are relative to the current time. By default one
|
851
|
+
* day worth of data will be printed.
|
852
|
+
*
|
853
|
+
* -e|--end seconds (default now)
|
854
|
+
* The time when the exported range should end. Time in
|
855
|
+
* seconds since epoch.
|
856
|
+
*
|
857
|
+
* -m|--maxrows rows (default 400 rows)
|
858
|
+
* This works like the -w|--width parameter of rrdgraph. In
|
859
|
+
* fact it is exactly the same, but the parameter was renamed
|
860
|
+
* to describe its purpose in this module. See rrdgraph
|
861
|
+
* documentation for details.
|
862
|
+
*
|
863
|
+
* --step value (default automatic)
|
864
|
+
* See the rrdgraph manpage documentation.
|
865
|
+
*
|
866
|
+
* DEF:vname=rrd:ds-name:CF
|
867
|
+
* See rrdgraph documentation.
|
868
|
+
*
|
869
|
+
* CDEF:vname=rpn-expression
|
870
|
+
* See rrdgraph documentation.
|
871
|
+
*
|
872
|
+
* XPORT:vname::legend
|
873
|
+
* At least one XPORT statement should be present. The values
|
874
|
+
* referenced by vname are printed. Optionally add a legend.
|
875
|
+
*/
|
876
|
+
VALUE rrdtool_xport(VALUE self, VALUE args)
|
877
|
+
{
|
878
|
+
s_arr a;
|
879
|
+
unsigned long i, j, k, step, col_cnt;
|
880
|
+
rrd_value_t *rrd_data;
|
881
|
+
char **legend_v;
|
882
|
+
VALUE data, legends, rval = Qnil;
|
883
|
+
time_t start, end;
|
884
|
+
#ifdef R_RRD_DBG
|
885
|
+
char buf[NUM_BUF_SZ+1];
|
886
|
+
#endif
|
887
|
+
|
888
|
+
reset_rrd_state();
|
889
|
+
|
890
|
+
a = s_arr_new(self, false, true, args);
|
891
|
+
|
892
|
+
rrd_xport(a.len, a.strs, 0, &start, &end, &step,
|
893
|
+
&col_cnt, &legend_v, &rrd_data);
|
894
|
+
|
895
|
+
s_arr_del(a);
|
896
|
+
|
897
|
+
RRD_CHECK_ERROR;
|
898
|
+
|
899
|
+
/* process the data .. get the legends first */
|
900
|
+
legends = rb_ary_new();
|
901
|
+
for (i = 0; i < col_cnt; i++) {
|
902
|
+
rb_ary_push(legends, rb_str_new2(legend_v[i]));
|
903
|
+
#ifdef R_RRD_DBG
|
904
|
+
snprintf(buf, NUM_BUF_SZ, "xport: names: n=[%s]", legend_v[i]);
|
905
|
+
buf[NUM_BUF_SZ] = 0;
|
906
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
907
|
+
#endif
|
908
|
+
free(legend_v[i]);
|
909
|
+
}
|
910
|
+
free(legend_v);
|
911
|
+
|
912
|
+
/* step over the 2d array containing the data */
|
913
|
+
k = 0;
|
914
|
+
data = rb_ary_new();
|
915
|
+
for (i = start; i <= end; i += step) {
|
916
|
+
VALUE line = rb_ary_new2(col_cnt);
|
917
|
+
for (j = 0; j < col_cnt; j++) {
|
918
|
+
rb_ary_store(line, j, rb_float_new(rrd_data[k]));
|
919
|
+
k++;
|
920
|
+
}
|
921
|
+
rb_ary_push(data, line);
|
922
|
+
}
|
923
|
+
free(rrd_data);
|
924
|
+
|
925
|
+
/* now prepare an array for ruby to chew on .. */
|
926
|
+
rval = rb_ary_new2(6);
|
927
|
+
rb_ary_store(rval, 0, LONG2NUM(start));
|
928
|
+
rb_ary_store(rval, 1, LONG2NUM(end));
|
929
|
+
rb_ary_store(rval, 2, UINT2NUM(step));
|
930
|
+
rb_ary_store(rval, 3, UINT2NUM(col_cnt));
|
931
|
+
rb_ary_store(rval, 4, legends);
|
932
|
+
rb_ary_store(rval, 5, data);
|
933
|
+
|
934
|
+
return rval;
|
935
|
+
}
|
936
|
+
|
937
|
+
|
938
|
+
|
939
|
+
/*
|
940
|
+
* Document-method: graph
|
941
|
+
*
|
942
|
+
* call-seq:
|
943
|
+
* RRDtool.graph(arg_array) -> [Qnil|Qtrue]
|
944
|
+
*
|
945
|
+
* The graph function generates an image from the data values in an RRD.
|
946
|
+
*
|
947
|
+
*
|
948
|
+
*/
|
949
|
+
VALUE rrdtool_graph(VALUE self, VALUE args)
|
950
|
+
{
|
951
|
+
s_arr a;
|
952
|
+
char **calcpr, **p;
|
953
|
+
VALUE result, print_results;
|
954
|
+
int xsize, ysize;
|
955
|
+
double ymin, ymax;
|
956
|
+
|
957
|
+
reset_rrd_state();
|
958
|
+
|
959
|
+
a = s_arr_new(self, false, true, args);
|
960
|
+
|
961
|
+
rrd_graph(a.len, a.strs, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
|
962
|
+
|
963
|
+
s_arr_del(a);
|
964
|
+
|
965
|
+
RRD_CHECK_ERROR;
|
966
|
+
|
967
|
+
result = rb_ary_new2(3);
|
968
|
+
print_results = rb_ary_new();
|
969
|
+
p = calcpr;
|
970
|
+
for (p = calcpr; p && *p; p++) {
|
971
|
+
rb_ary_push(print_results, rb_str_new2(*p));
|
972
|
+
free(*p);
|
973
|
+
}
|
974
|
+
free(calcpr);
|
975
|
+
|
976
|
+
rb_ary_store(result, 0, print_results);
|
977
|
+
rb_ary_store(result, 1, INT2NUM(xsize));
|
978
|
+
rb_ary_store(result, 2, INT2NUM(ysize));
|
979
|
+
return result;
|
980
|
+
}
|
981
|
+
|
982
|
+
|
983
|
+
/*
|
984
|
+
* Document-method: info
|
985
|
+
*
|
986
|
+
* call-seq:
|
987
|
+
* rrd.info -> [Qnil|T_HASH]
|
988
|
+
*
|
989
|
+
* The info function prints the header information from an RRD in a
|
990
|
+
* parsing friendly format.
|
991
|
+
*
|
992
|
+
*/
|
993
|
+
VALUE rrdtool_info(VALUE self)
|
994
|
+
{
|
995
|
+
VALUE rrd; /* rrd database filename */
|
996
|
+
VALUE rval; /* our result */
|
997
|
+
info_t *data, *p; /* this is what rrd_info()returns */
|
998
|
+
|
999
|
+
reset_rrd_state();
|
1000
|
+
|
1001
|
+
rrd = rb_iv_get(self, "@rrdname");
|
1002
|
+
data = rrd_info_r(STR2CSTR(rrd));
|
1003
|
+
|
1004
|
+
RRD_CHECK_ERROR;
|
1005
|
+
|
1006
|
+
rval = rb_hash_new();
|
1007
|
+
while (data) {
|
1008
|
+
VALUE key = rb_str_new2(data->key);
|
1009
|
+
switch (data->type) {
|
1010
|
+
case RD_I_VAL:
|
1011
|
+
if (isnan(data->value.u_val)) {
|
1012
|
+
rb_hash_aset(rval, key, rb_str_new2("Nil"));
|
1013
|
+
}
|
1014
|
+
else {
|
1015
|
+
rb_hash_aset(rval, key, rb_float_new(data->value.u_val));
|
1016
|
+
}
|
1017
|
+
break;
|
1018
|
+
case RD_I_CNT:
|
1019
|
+
rb_hash_aset(rval, key, UINT2NUM(data->value.u_cnt));
|
1020
|
+
break;
|
1021
|
+
case RD_I_STR:
|
1022
|
+
rb_hash_aset(rval, key, rb_str_new2(data->value.u_str));
|
1023
|
+
free(data->value.u_str);
|
1024
|
+
break;
|
1025
|
+
default:
|
1026
|
+
rb_hash_aset(rval, key, rb_str_new2("-UNKNOWN-"));
|
1027
|
+
}
|
1028
|
+
p = data;
|
1029
|
+
data = data->next;
|
1030
|
+
free(p);
|
1031
|
+
}
|
1032
|
+
return rval;
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
|
1036
|
+
/*
|
1037
|
+
* return the rrdname instance variable
|
1038
|
+
*/
|
1039
|
+
static VALUE rrdtool_rrdname(VALUE self) {
|
1040
|
+
VALUE rrdname;
|
1041
|
+
rrdname = rb_iv_get(self, "@rrdname");
|
1042
|
+
return rrdname;
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
|
1046
|
+
/*
|
1047
|
+
* class initialization makes a context
|
1048
|
+
*/
|
1049
|
+
static VALUE rrdtool_initialize(VALUE self, VALUE ofname) {
|
1050
|
+
#ifdef R_RRD_DBG
|
1051
|
+
char buf[NUM_BUF_SZ+1];
|
1052
|
+
#endif
|
1053
|
+
VALUE rrdname;
|
1054
|
+
|
1055
|
+
rrdname = StringValue(ofname);
|
1056
|
+
rb_iv_set(self, "@rrdname", rrdname);
|
1057
|
+
#ifdef R_RRD_DBG
|
1058
|
+
snprintf(buf, NUM_BUF_SZ, "rrdname=[%s]", STR2CSTR(rrdname));
|
1059
|
+
buf[NUM_BUF_SZ] = 0;
|
1060
|
+
_dbug(R_RRD_DEBUG_SIM, buf);
|
1061
|
+
#endif
|
1062
|
+
return self;
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
|
1066
|
+
/*
|
1067
|
+
* Define and create the Ruby objects and methods
|
1068
|
+
*/
|
1069
|
+
void Init_RRDtool()
|
1070
|
+
{
|
1071
|
+
cRRDtool = rb_define_class("RRDtool", rb_cObject);
|
1072
|
+
|
1073
|
+
rb_eRRDtoolError = rb_define_class("RRDtoolError", rb_eStandardError);
|
1074
|
+
|
1075
|
+
rb_define_method(cRRDtool, "initialize", rrdtool_initialize, 1);
|
1076
|
+
rb_define_method(cRRDtool, "rrdname", rrdtool_rrdname, 0);
|
1077
|
+
rb_define_method(cRRDtool, "create", rrdtool_create, 3);
|
1078
|
+
rb_define_method(cRRDtool, "update", rrdtool_update, 2);
|
1079
|
+
rb_define_method(cRRDtool, "fetch", rrdtool_fetch, 1);
|
1080
|
+
rb_define_method(cRRDtool, "restore", rrdtool_restore, 3);
|
1081
|
+
rb_define_method(cRRDtool, "tune", rrdtool_tune, 1);
|
1082
|
+
rb_define_method(cRRDtool, "last", rrdtool_last, 0);
|
1083
|
+
rb_define_method(cRRDtool, "first", rrdtool_first, 1);
|
1084
|
+
rb_define_method(cRRDtool, "resize", rrdtool_resize, 1);
|
1085
|
+
rb_define_method(cRRDtool, "info", rrdtool_info, 0);
|
1086
|
+
#ifdef HAVE_RRD_DUMP_R_2
|
1087
|
+
rb_define_method(cRRDtool, "dump", rrdtool_dump, 1);
|
1088
|
+
#endif
|
1089
|
+
/* version() is really a library function */
|
1090
|
+
rb_define_singleton_method(cRRDtool, "version", rrdtool_version, 0);
|
1091
|
+
rb_define_singleton_method(cRRDtool, "graph", rrdtool_graph, 1);
|
1092
|
+
rb_define_singleton_method(cRRDtool, "xport", rrdtool_xport, 1);
|
1093
|
+
}
|