RubyRRDtool 0.6.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.
- 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
|
+
}
|