package RRDTool::Creator ; # ============================================ # # Jacquelin Charbonnel - CNRS/LAREMA # # $Id: Creator.pm 410 2008-03-11 21:45:09Z jaclin $ # # ---- # # A generic abstract creator for round robin databases (RRD) # # ---- # $LastChangedDate: 2008-03-11 22:45:09 +0100 (Tue, 11 Mar 2008) $ # $LastChangedRevision: 410 $ # $LastChangedBy: jaclin $ # $URL: https://svn.math.cnrs.fr/jaclin/src/pm/RRDTool-Creator/Creator.pm $ # # ============================================ require Exporter ; @ISA = qw(Exporter); @EXPORT=qw() ; use Carp ; use RRDTool::OO ; use strict ; use warnings ; our $VERSION = "0.9" ; # $LastChangedRevision: 410 $ $Carp::CarpLevel = 1; my $InSeconds = { "s" => 1 , "mn" => 60 , "h" => 60*60 , "d" => 60*60*24 , "w" => 60*60*24*7 , "m" => 60*60*24*30 # supposed 30 days , "q" => 60*60*24*30*3 # 3 months , "y" => 60*60*24*30*12 # 12 months } ; sub _getkey { my ($key) = @_ ; $Carp::CarpLevel = 2 ; my @keys = grep /^$key/i,keys %$InSeconds ; croak "unknown '$key' unit" if scalar(@keys)==0 ; croak "ambigous '$key' unit (".join(",",@keys)." ?)" if scalar(@keys)>1 ; return lc($keys[0]) ; } sub _inSeconds { my($duration,$allowed) = @_ ; $Carp::CarpLevel = 2 ; my ($num,$unit) = $duration=~/^\s*(\d+)\s*([a-zA-Z]+)\s*$/ or return undef ; my %allowed = map { $_ => 1 } @$allowed ; croak "unit '$unit' not allowed" unless exists $allowed{lc($unit)} ; my $key = _getkey($unit) ; return $num * $InSeconds->{$key} ; } #-- sub _new { my($type,$units,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; for my $k ("step") { croak "argument '$k' is missing" unless exists $h{lc($k)} ; } my $step = $h{"step"} ; my $s_step = _inSeconds($step,$units) or croak "bad format for step '$step'" ; my $this = { "step" => $s_step , "DS" => [] , "RRA" => [] } ; bless $this,$type ; return $this ; } #------------------------------- sub _set_filename { my($this,$filename) = @_ ; $this->{"filename"} = $filename ; } #------------------------------- sub add { my($this,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; # normalisation if (exists $h{"cfunc"}) { $h{"cf"} = $h{"cfunc"} ; delete $h{"cfunc"} ; } push(@{$this->{"CF"}},$h{"cf"}) if exists $h{"cf"} ; } #------------------------------- sub add_RRA { my($this,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; for my $k ("duration") { croak "'$k' argument is missing" unless exists $h{lc($k)} ; } my $duration = $h{"duration"} ; croak "possible duration are : " .join(",",keys %{$this->{"allowed_RRA_duration"}}) unless exists $this->{"allowed_RRA_duration"}{$duration} ; push(@{$this->{"RRA"}},\%h) ; } #------------------------------- sub add_data_source { add_DS(@_) ; } sub add_DS { my($this,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; # normalisation if (exists $h{"name"}) { $h{"ds_name"} = $h{"name"} ; delete $h{"name"} ; } if (exists $h{"type"}) { $h{"dst"} = $h{"type"} ; delete $h{"type"} ; } $h{"min"} = "U" unless exists $h{"min"} ; $h{"max"} = "U" unless exists $h{"max"} ; $h{"heartbeat"} = 2*$this->{"step"} unless exists $h{"heartbeat"} ; for my $k ("ds_name","DST") { croak "'$k' argument is missing" unless exists $h{lc($k)} ; } push(@{$this->{"DS"}},\%h) ; } #------------------------------- sub add_compute_DS { my($this,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; # normalisation if (exists $h{"name"}) { $h{"ds_name"} = $h{"name"} ; delete $h{"name"} ; } for my $k ("ds_name","rpn_expression") { croak "'$k' argument is missing" unless exists $h{lc($k)} ; } push(@{$this->{"DS"}},\%h) ; } #------------------------------- sub compile { my($this) = @_ ; my $rrd = RRDTool::OO->new("file" => $this->{"filename"}); my @arg = () ; push(@arg,("step" => $this->{"step"})) ; for my $ds (@{$this->{"DS"}}) { push(@arg,("data_source", { "name" => $ds->{"ds_name"} , "type" => $ds->{"dst"} , "heartbeat" => $ds->{"heartbeat"} , "min" => $ds->{"min"} , "max" => $ds->{"max"} } ) ) } push(@arg,("archive", { "cfunc" => "LAST" , "cpoints" => 1 , "rows" => $this->{"rows"} } )) ; for my $cpoint (@{$this->{"RRA"}}) { for my $cfunc (@{$this->{"CF"}}) { push(@arg,("archive", { "cfunc" => $cfunc , "cpoints" => $InSeconds->{substr($cpoint->{"duration"},0,1)}/($this->{"step"}*$this->{"rows"}) , "rows" => $this->{"rows"} } ) ) } } $this->{"OO_create_arg"} = \@arg ; return @arg ; } #------------------------------- sub create { my($this,%h) = @_ ; %h = map { /^-/ ? lc(substr($_,1)) : $_ ; } %h ; # normalisation if (exists $h{"file"}) { $h{"filename"} = $h{"file"} ; delete $h{"file"} ; } $this->{"filename"} = $h{"filename"} if exists $h{"filename"} ; $this->{"OO_create_arg"} = $h{"OO_create_arg"} if exists $h{"OO_create_arg"} ; $this->compile() unless defined $this->{"OO_create_arg"} ; my $rrd = RRDTool::OO->new("file" => $h{"filename"}); $rrd->create(@{$this->{"OO_create_arg"}}) ; } __END__ =head1 NAME C - Creators for round robin databases (RRD) =head1 COMPONENTS C - A generic abstract creator for round robin databases (RRD) C - creates a RRD with a default archive of primary points for an hour C - creates a RRD with a default archive of primary points for a day C - creates a RRD with a default archive of primary points for a week C - creates a RRD with a default archive of primary points for a month C - creates a RRD with a default archive of primary points for a quarter C - creates a RRD with a default archive of primary points for a year =head1 SYNOPSIS use RRDTool::Creator::DayPDP ; # make a creator $creator = new RRDTool::Creator::DayPDP(-step => "30mn") ; # add data sources in the specifications of the RRD $creator->add_DS( -ds_name => "cpu" , -DST => "GAUGE" , -min => 0 , -max => 100 ) ; $creator->add_DS( -ds_name => "swap" , -DST => "GAUGE" ) ; # add archives in the specifications of the RRD $creator->add_RRA(-duration => "week") ; $creator->add_RRA(-duration => "month") ; # add some consolidation functions in the specifications of the RRD $creator->add(-CF => "MAX") ; $creator->add(-CF => "AVERAGE") ; # create the RRD file $creator->create(-filename => "/var/rrdtool/vmstat.rrd") ; =head1 DESCRIPTION The C objects are specific creators for different kind of RRD files. They are based on the Round Robin Database Tool (L) and on the Perl module L. =head1 NOTES C tries to be compatible with both the official RRDTool documentation and the C module. It is why some functions and some arguments have two possible names (in this case, the main name is conform to the official documentation and the auxiliary one is for compatibility with the C module). =cut =head1 COMMON METHODS =head2 add_data_source See add_DS =head2 add_DS (auxiliary name: add_data_source) Add a data source in the RRD specifications. Its arguments are : =over 4 =item B (auxiliary name: B) (I) The name of the data source. =item B (auxiliary name: B) (I) The data source type : C, C, C or C (see L). =item B (I) The maximum number of seconds that may pass between two updates of this data source before the value of the data source is assumed to be *UNKNOWN*. Default is 2*step. =item B (I) The expected minimum value for data supplied by a data source. Any value outside the defined range will be regarded as *UNKNOWN*. Default is "U" for unknown. =item B (I) The expected maximum value for data supplied by a data source. Any value outside the defined range will be regarded as *UNKNOWN*. Default is "U" for unknown. $creator->add_DS( -ds_name => "cpu" , -DST => "GAUGE" , -min => 0 , -max => 100 ) ; =back =head2 add_compute_DS (not yet implemented) Add a data source with computed primary data points (it is a DS with DST equal to C) in the RRD specifications. Its arguments are : =over 4 =item B (auxiliary name: B) (I) The name of the data source. =item B (I) RPN expression that defines formula to compute PDP of this DS. =back =head2 B (auxiliary name: B) Add a round robin archive in the RRD specifications. =over 4 =item B (I) The duration of the archive. Possible values are : "day", "week", "month", "quarter" and "year". =item B (I) The xfiles factor (see ) $creator->add_RRA(-duration => "day") ; =back =head2 add Add some global attributes in the RRD specifications. =over 4 =item B (auxiliary name: B) Add a consolidation function (C, C, C, C... - see ), for each RRA (except the default RRA) in the RRD specifications. $creator->add(-CF => "AVERAGE") ; =back =head2 B Compute the argument for the function C of the underlaying RRDTool::OO object. Useful for debugging, this function also allows to customize the command passed to rrdtool. Return this argument (a list). @args = $creator->compile() ; =head2 B Create the RRD on the disk. =over 4 =item B (auxiliary name: B) (I) The name of the file to create. =item B (I) The argument passed to the function create of the underlaying RRDTool::OO object (this is the value returned by the previous function C). In normal case, this argument isn't provided, and its value is compiled from the current stored data. $creator->create(-filename => "/tmp/15s.rrd") ; which can be break up to : @args = $creator->compile() ; # possible manual modification on @args here... $creator->create(-filename => "/tmp/15s.rrd", -OO_create_arg => \@args) ; =back =head1 SUB-OBJECTS Each sub-objects of C creates a RRD with one default archive (RRA) made of primary data points (PDP). More RAA can then be added. The constructor neads an argument named C which is the period of acquisition. The time unit of the step depends of the sub-object. =head2 RRDTool::Creator::HourPDP The default RRA stores primary data points for an hour. More RRA can be added for a day, a week, a month, a quarter and a year. The created RRD is for an acquisition period much less than an hour, typically about some seconds or a few minutes. So, the step unit for its constructor argument is second(s) or minute(mn). $creator = new RRDTool::Creator::HourPDP(-step => "30s") ; $creator->add_RRA(-duration => "day") ; $creator->add_RRA(-duration => "week") ; $creator->add_RRA(-duration => "month") ; $creator->add_RRA(-duration => "quarter") ; $creator->add_RRA(-duration => "year") ; =head2 RRDTool::Creator::DayPDP The default RRA stores primary data points for a day. More RRA can be added for a week, a month, a quarter and a year. The created RRD is for an acquisition period much less than a day, typically about some minutes or a few hours. So, the natural step units for its constructor argument are the minute(mn) and hour(h), although second(s) is allowed. $creator = RRDTool::Creator::DayPDP(-step => "10mn") ; $creator->add_RRA(-duration => "week") ; $creator->add_RRA(-duration => "month") ; $creator->add_RRA(-duration => "quarter") ; $creator->add_RRA(-duration => "year") ; =head2 RRDTool::Creator::WeekPDP The default RRA stores primary data points for a week. More RRA can be added for a month, a quarter and a year. The created RRD is for an acquisition period much less than a week, typically about some hours. So, the natural step unit for its constructor argument is the hour(h), although second(s), minute(mn) and day(d) are allowed. $creator = RRDTool::Creator::WeekPDP(-step => "4h") ; $creator->add_RRA(-duration => "month") ; $creator->add_RRA(-duration => "quarter") ; $creator->add_RRA(-duration => "year") ; =head2 RRDTool::Creator::MonthPDP The default RRA stores primary data points for a month. More RRA can be added for a quarter and a year. The created RRD is for an acquisition period much less than a month, typically about some hours or a few days. So, the natural step unit for its constructor argument are hour(h) and day(d), although second(s), minute(m) and week(w) are allowed. $creator = RRDTool::Creator::MonthPDP(-step => "1d") ; $creator->add_RRA(-duration => "quarter") ; $creator->add_RRA(-duration => "year") ; =head2 RRDTool::Creator::QuarterPDP The default RRA stores primary data points for a quarter. More RRA can be added for a year. The created RRD is for an acquisition period much less than a quarter, typically about some days or a few weeks. So, the natural step unit for its constructor argument are day(d) and week(w), although second(s), minute(m), hour(h) and month(m) are allowed. $creator = RRDTool::Creator::QuarterPDP(-step => "3d") ; $creator->add_RRA(-duration => "year") ; =head2 RRDTool::Creator::YearPDP The default RRA stores primary data points for a year. No more RRA can be added. The created RRD is for an acquisition period much less than a year, typically about some days, a few weeks or months. So, the natural step unit for its constructor argument are day(d), week(w) and month(m), although second(s), minute(m), hour(h) and quarter(q) are allowed. $creator = RRDTool::Creator::YearPDP(-step => "1w") ; =head1 EXAMPLES =head2 EXAMPLE 1 To create a RRD to store percent cpu load and swap use, gathering every 10mn, with the aim of graphing average and max values daily, weekly, monthly and yearly : $creator = new RRDTool::Creator::DayPDP(-step => "10mn") ; $creator->add_DS( -ds_name => "cpu" , -DST => "GAUGE" , -min => 0 , -max => 100 ) ; $creator->add_DS( -ds_name => "swap" , -DST => "GAUGE" , -min => 0 ) ; $creator->add(-CF => "AVERAGE") ; $creator->add(-CF => "MAX") ; $creator->add_RRA(-duration => "week") ; $creator->add_RRA(-duration => "month") ; $creator->add_RRA(-duration => "year") ; $creator->create(-filename => "vmstat.rrd") ; =head2 EXAMPLE 2 To create a RRD to store number of spams and total mails received every days, with the aim of graphing average and max values quarterly and yearly : $creator = new RRDTool::Creator::QuarterPDP(-step => "1d") ; $creator->add_DS( -ds_name => "spams" , -DST => "GAUGE" , -min => 0 ) ; $creator->add_DS( -ds_name => "mails" , -DST => "GAUGE" , -min => 0 ) ; $creator->add(-CF => "AVERAGE") ; $creator->add(-CF => "MAX") ; $creator->add_RRA(-duration => "year") ; $creator->create(-filename => "mail.rrd") ; =head2 EXAMPLE 3 To create a RRD to store disk usage every 4 hours, with the aim of graphing max values weekly and yearly : $creator = new RRDTool::Creator::WeekPDP(-step => "4h") ; $creator->add_DS( -ds_name => "/home" , -DST => "GAUGE" , -min => 0 , -max => 100 ) ; $creator->add_DS( -ds_name => "/var" , -DST => "GAUGE" , -min => 0 , -max => 100 ) ; $creator->add(-CF => "MAX") ; $creator->add_RRA(-duration => "year") ; $creator->create(-filename => "df.rrd") ; =head1 SEE ALSO L, L =head1 AUTHOR Jacquelin Charbonnel, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc RRDTool-Creator You can also look for information at: =over 4 =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =item * RT: CPAN's request tracker L =item * Search CPAN L =back =head1 COPYRIGHT & LICENSE Copyright Jacquelin Charbonnel E jacquelin.charbonnel at math.cnrs.fr E This software is governed by the CeCILL-C license under French law and abiding by the rules of distribution of free software. You can use, modify and/ or redistribute the software under the terms of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors have only limited liability. In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or developing or reproducing the software by the user in light of its specific status of free software, that may mean that it is complicated to manipulate, and that also therefore means that it is reserved for developers and experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the software's suitability as regards their requirements in conditions enabling the security of their systems and/or data to be ensured and, more generally, to use and operate it in the same conditions as regards security. The fact that you are presently reading this means that you have had knowledge of the CeCILL-C license and that you accept its terms.