rrdreel

Check-in [fc74e44c02]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Switch to tcl implementation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:fc74e44c027918afe61a5c2eb2a8945c126c3a7ff06fe871b27f070d1b49978f
User & Date: jef 2018-08-29 21:06:06
Context
2018-08-29
21:12
Simplify rra code check-in: 7cf461ae72 user: jef tags: trunk
21:06
Switch to tcl implementation check-in: fc74e44c02 user: jef tags: trunk
21:05
Switch to tcl implementation check-in: 2eb0e0bfb3 user: jef tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Deleted backends/base.pm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package backends::base;

=head1 NAME

backends::base - base component for monitoring backends

=head1 OBJECT METHODS

=over 4

=item rrd_file

Return the path of the RRD database

=item graph_file

Return the path of the PNG file

=item cleanup

Perform backend cleanup, removing RDD and PNG file

=item timeslots

Return an array reference of timeslots supported by the
backend. Each timeslot is an hash reference made of a
C<label> string value and a C<range> integer value
representing an amount of seconds.

=item timeslot_set ( TS )

Set the current timeslot to TS

=item step

Return the backend's RRD step value

=item rras

Return a list of RRAs for RRD creation

=back

=cut

use strict;
use warnings;
use 5.010;
use File::Path qw(rmtree);
use File::Temp qw();
use POSIX qw(ceil);

sub tempdir {
        state $dir = File::Temp::tempdir();
        return $dir;
}

sub new {
        my ($class, @args) = @_;

        my %args = @args;

        my $this = {};
        my $defaults;
        {
                no strict 'refs';
                $defaults = ${$class . "::defaults"};
        }

        foreach my $key (keys %{ $defaults }) {
                $this->{$key} = $args{$key} // $defaults->{$key};
        }
        bless($this, $class);
        $this->timeslot_set($this->timeslots()->[0]);

        return $this;
}

sub rrd_file {
        my ($this) = @_;

        return tempdir() . "/db.rrd";
}

sub graph_file {
        my ($this) = @_;

        return tempdir() . "/graph.png";
}

sub cleanup {
        my ($this) = @_;

        rmtree(tempdir());
}

sub timeslots {
        my ($this) = @_;

        return [
                {
                        label => "last 5 mns",
                        range => 300
                },
                {
                        label => "last 15 mns",
                        range => 900
                },
                {
                        label => "last 30 mns",
                        range => 1800
                },
                {
                        label => "last hour",
                        range => 3600
                },
                {
                        label => "last 12 hours",
                        range => 42300
                },
                {
                        label => "last day",
                        range => 86400
                }
        ];
}

sub timeslot_set {
        my ($this, $ts) = @_;

        $this->{ts} = $ts;
}

sub step {
        my ($this) = @_;

        return $this->{step};
}

sub rras {
        my ($this) = @_;

        my $max = sub {
                $_[0] < $_[1] ? $_[1] : $_[0];
        };

        my %rras = ();
        my $steps;
        my $rows;
        foreach my $ts (@{ $this->timeslots() }) {
                # compute the right amount of steps / rows for this timeslot
                my $ndata = ceil($ts->{range} / $this->{step});
                if ($ndata <= $this->{graph_width}) {
                        ($steps, $rows) = (1, $ndata);
                } else {
                        ($steps, $rows) = (ceil($ndata / $this->{graph_width}), $this->{graph_width});
                }

                # store new RRA / merge if another RRA is already using a same amount of steps
                if (exists $rras{$steps}) {
                        $rras{$steps} = $max->($rows, $rras{$steps});
                } else {
                        $rras{$steps} = $rows;
                }
        }

        return map { sprintf("RRA:AVERAGE:0.5:%d:%d", $_, $rras{$_}) } keys %rras;
}
1;
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































Deleted backends/gauge.pm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package backends::gauge;

=head1 NAME

backends::value - Monitor backend for a single gauge value

=head1 CONSTRUCTOR

=over 4

=item new ( [ARGS] )

Creates a c<backends::gauge> object.

Allowed arguments:

=over 8

=item graph_width

PNG graph width (default 600)

=item graph_height

PNG graph height (default 120)

=item step

delay in seconds between each values (default 1)

=item title

main title of the graph (default "")

=item vlabel

vertical left label (default "")

=item legend

legend of the monitored gauge (default "")

=item unit

unit of the monitored gauge (default "")

=back

=back

=head1 OBJECT METHODS

=over 4

=item rrd_create

Create the RRD file.

=item rrd_update

Update the RRD file, reading a gauge value from STDIN.
This backend expect to recieve a single value per line.

=item graph_update

Update the graph for a specific RANGE.

=back

=cut

use strict;
use warnings;
use 5.010;
use RRDs;
use List::MoreUtils qw(uniq);
use base ("backends::base");

our $defaults = {
        graph_width => 600,
        graph_height => 120,
        step => 1,
        title => "",
        vlabel => "",
        legend => "",
        unit => ""
};

sub rrd_create {
        my ($this) = @_;

        my $heartbeat = $this->{step} * 2;
        RRDs::create $this->rrd_file(),
                  "-bN",
                  "-s$this->{step}",
                  "DS:gauge:GAUGE:$heartbeat:U:U",
                  $this->rras();
        die RRDs::error if RRDs::error;
}

sub rrd_update {
        my ($this) = @_;

        my $value = <STDIN>;
        chomp $value;
        RRDs::update $this->rrd_file(), "-t", "gauge", "N:$value";
        die RRDs::error if RRDs::error;
}

sub graph_update {
        my ($this) = @_;
        state $lastrange = -1;

        my @args = (
                $this->graph_file(),
                "-s -$this->{ts}->{range}",
                "-t $this->{title}",
                "-h", $this->{graph_height}, "-w", $this->{graph_width},
                "-l 0",
                "-a", "PNG",
                "-v $this->{vlabel}",
                sprintf("DEF:gauge=%s:gauge:AVERAGE", $this->rrd_file()),
                "AREA:gauge#32CD32:$this->{legend}",
                "LINE1:gauge#336600",
                "GPRINT:gauge:MAX: Max\\: %5.1lf %s",
                "GPRINT:gauge:AVERAGE: Avg\\: %5.1lf %S",
                "GPRINT:gauge:LAST: Current\\: %5.1lf %S$this->{unit}\\n",
                "HRULE:0#000000");

        push @args, "--lazy" if $lastrange == $this->{ts}->{range};
        RRDs::graph(@args);
        die RRDs::error if RRDs::error;

        $lastrange = $this->{ts}->{range};
}

1;
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































Deleted backends/interface.pm.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package backends::interface;

=head1 NAME

backends::interface - Monitor backend for network interfaces

=head1 CONSTRUCTOR

=over 4

=item new ( [ARGS] )

Creates a c<backends::interface> object.

Allowed arguments:

=over 8

=item graph_width

PNG graph width (default 600)

=item graph_height

PNG graph height (default 120)

=item step

delay in seconds between each values (default 1)

=item title

main title of the graph (default "Traffic on interface")

=item vlabel

vertical left label (default "Bits per second")

=item in_legend

legend for the input values (default "In")

=item in_unit

unit of the input values (default "bits")

=item out_legend

legend for the output values (default "Out")

=item out_unit

unit of the output values (default "bits")

=back

=back

=head1 OBJECT METHODS

=over 4

=item rrd_create

Create the RRD file.

=item rrd_update

Update the RRD file, reading a counter value from STDIN.
This backend expect to recieve a single value per line.

=item graph_update

Update the graph for a specific RANGE.

=back

=cut

use strict;
use warnings;
use 5.010;
use RRDs;
use List::MoreUtils qw(uniq);
use base ("backends::base");

our $defaults = {
        graph_width => 600,
        graph_height => 120,
        step => 1,
        title => "Traffic on interface",
        vlabel => "Bits per second",
        in_legend => "In",
        in_unit => "bits",
        out_legend => "Out",
        out_unit => "bits"
};

sub rrd_create {
        my ($this) = @_;

        my $heartbeat = $this->{step} * 2;
        RRDs::create $this->rrd_file(),
                  "-bN",
                  "-s$this->{step}",
                  "DS:in:DERIVE:$heartbeat:0:U",
                  "DS:out:DERIVE:$heartbeat:0:U",
                  $this->rras();
        die RRDs::error if RRDs::error;
}

sub rrd_update {
        my ($this) = @_;

        my ($in, $out) = split(/\s+/, <STDIN>, 3);
        RRDs::update $this->rrd_file(), "-t", "in:out", "N:$in:$out";
        die RRDs::error if RRDs::error;
}

sub graph_update {
        my ($this) = @_;
        state $lastrange = -1;

        my @args = (
                $this->graph_file(),
                "-s -$this->{ts}->{range}",
                "-t $this->{title}",
                "-h", $this->{graph_height}, "-w", $this->{graph_width},
                "-l 0",
                "-a", "PNG",
                "-v $this->{vlabel}",
                sprintf("DEF:in=%s:in:AVERAGE", $this->rrd_file()),
                sprintf("DEF:out=%s:out:AVERAGE", $this->rrd_file()),
                "CDEF:out_neg=out,-1,*",
                "AREA:in#32CD32:$this->{in_legend}",
                "LINE1:in#336600",
                "GPRINT:in:MAX:  Max\\: %.1lf %s",
                "GPRINT:in:AVERAGE: Avg\\: %.1lf %S",
                "GPRINT:in:LAST: Current\\: %.1lf %S$this->{in_unit}\\n",
                "AREA:out_neg#4169E1:$this->{out_legend}",
                "LINE1:out_neg#0033CC",
                "GPRINT:out:MAX:  Max\\: %.1lf %S",
                "GPRINT:out:AVERAGE: Avg\\: %.1lf %S",
                "GPRINT:out:LAST: Current\\: %.1lf %S$this->{out_unit}\\n",
                "HRULE:0#000000");

        push @args, "--lazy" if $lastrange == $this->{ts}->{range};
        RRDs::graph(@args);
        die RRDs::error if RRDs::error;

        $lastrange = $this->{ts}->{range};
}

1;
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<