jablonka.czprosek.czf

hotsanic

Subversion Repositories:
[/] [branches/] [HotSaNIC-0.5.0-pre6/] [lib/] [HotSaNICdiagram.pm] - Rev 15 Go to most recent revision

Compare with Previous - Blame - Download


#
# $Id: HotSaNICdiagram.pm,v 1.29 2004/09/19 10:07:19 bernisys Exp $
#

package HotSaNICdiagram;

use RRDs;

($VERSION = '$Revision: 1.29 $') =~ s/.*(\d+\.\d+).*/$1/;

my @Weekday=("Sun","Mon","Tue","Wed","Thu","Fri","Sat");

######################################################################
#
# evaluates some diagram properties from the given range
#
# Usage:
#   ($description,$file_description,$build_interval,$diagram_range,$timestring)=get_diagram_properties($range);
#
sub get_diagram_properties {
  my ($range)=@_;
  my ($descr,$file,$build,$fullrange);
  if    ($range eq "1h")     { $descr="hour";    $file=$descr; $build=0;     $fullrange=3600; }
  elsif ($range eq "6h")     { $descr="6 hours"; $file="6h";   $build=30;    $fullrange=21600; }
  elsif ($range eq "1day")   { $descr="day";     $file=$descr; $build=120;   $fullrange=86400; }
  elsif ($range eq "1week")  { $descr="week";    $file=$descr; $build=1000;  $fullrange=604800; }
  elsif ($range eq "1month") { $descr="month";   $file=$descr; $build=4300;  $fullrange=2592000; }
  elsif ($range eq "1year")  { $descr="year";    $file=$descr; $build=52500; $fullrange=31536000; }

  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  $year+=1900;
  $mon++;
  if ($mon<10) { $mon="0".$mon; }
  if ($mday<10) { $mday="0".$mday; }
  if ($hour<10) { $hour="0".$hour; }
  if ($min<10) { $min="0".$min; }
  $buildtime="$Weekday[$wday] $year-$mon-$mday $hour:$min";

  return ($descr,$file,$build,$fullrange,$buildtime);
  }

######################################################################
#
# Creates a diagram from the options passed within a config hash
#
# Usage:
#   graph(%CONFIGHASH);
#
# Hints:
#   The hash has to contain the following items:
# 
#   %CONFIGHASH=( FILENAME => "full path to output file without suffix"
#                   FORMAT => "gif"  # ("png" or "gif")
#                 INTERVAL => <seconds between neccessary update>
#                    FORCE => 0 for automatic checking, >0 forces plot
#                    RANGE => plot range of diagram (1year 6h 1h ...)
#               DEBUGLEVEL => everything >1 plots complete optiin array
#                  OPTIONS => array of options that will be passed tpo RRDs
#                             assign it like this:  => [(@a1,@a2,...)]
#
sub graph {
  my %CONF=@_;

  my $FILE=$CONF{FILENAME}.".".$CONF{FORMAT};
  my $TEMPFILE=$CONF{FILENAME}."-temp.".$CONF{FORMAT};

  my @OPTIONS=@{$CONF{OPTIONS}};

  if (! -e $FILE) { $CONF{FORCE}++; }
  else { $CONF{FORCE}++ if time >= (stat($FILE))[9]+$CONF{INTERVAL}; }
  
  if ($CONF{FORCE} > 0) {
    if ($CONF{DEBUGLEVEL} > 1) { print join("\n",$TEMPFILE,@OPTIONS),"\n"; }
    my ($prints,$xs,$ys)=RRDs::graph $TEMPFILE,@OPTIONS;
    if ($ERROR = RRDs::error) { print time," ",$CONF{MODNAME},": $ERROR\n"; }
    else {
      rename $TEMPFILE,$FILE;
      printf "  %9s %4d x %4d %s\n", $CONF{RANGE},$xs,$ys,$FILE;
      }
    }
  }

sub check_args {
  my $OPT=0;
  $FORCE=0;
  $DEBUGLEVEL=-1;
  %PLOT=();
  foreach (@_) {
    $FORCE=1 if $_ eq "a";
    $DEBUGLEVEL=100 if $_ eq "d";
    if ($OPT==1) { $PLOT{$_}=1; $OPT=0; }
    $OPT=1 if $_ eq "g";
    if ( ($_ eq "?") or ($_ eq "h") ) {
      print "options:\n
      g <name>   only graph item <name>
                   (can be used multiple times, default: plot all)\n
      a          plot all time-graphs of selected items
                   (default: plot only expired graphs)\n
      d          enable debug mode (prints all graph options -
                   much output!)\n
      ? or h     display this help-text
      \n";
      exit;
      }
    }
  return ($FORCE,$DEBUGLEVEL,%PLOT);
  }

########################################
# get_common_options calculates an array of common module-specific and
# global diagram options to be passed to RRDs::graph. it accepts a hash 
# containing both modulespecific and global settings.
#
sub get_common_options {
  my %CONFIG=@_;
  my @OPTIONS=();
  if ($CONFIG{GRAPH_RIGID} == 1 ) { push @OPTIONS,"-r"; }
  if ($CONFIG{GRAPH_FORCE_LEGEND} == 1 ) { push @OPTIONS,"-F"; }
  if ($CONFIG{GRAPH_STYLE} eq "log" ) {
    push @OPTIONS,"-o";
    $CONFIG{GRAPH_MIN}=$CONFIG{GRAPH_MIN_LOG};
    }
  if (defined $CONFIG{GRAPH_BASE}) {
    if ( ($CONFIG{GRAPH_BASE} eq "percent") or ($CONFIG{GRAPH_BASE} eq "%") ) {
      if (defined $CONFIG{GRAPH_MAX}) { $CONFIG{GRAPH_MAX}*=100; }
      if (defined $CONFIG{GRAPH_MIN}) { $CONFIG{GRAPH_MIN}*=100; }
      }
    if ($CONFIG{GRAPH_BASE} eq "bits") {
      if (defined $CONFIG{GRAPH_MAX}) { $CONFIG{GRAPH_MAX}*=8; }
      if (defined $CONFIG{GRAPH_MIN}) { $CONFIG{GRAPH_MIN}*=8; }
      }
    elsif ($CONFIG{GRAPH_BASE} eq "ms") {
      if (defined $CONFIG{GRAPH_MAX}) { $CONFIG{GRAPH_MAX}/=1000; }
      if (defined $CONFIG{GRAPH_MIN}) { $CONFIG{GRAPH_MIN}/=1000; }
      }
    elsif ($CONFIG{GRAPH_BASE} eq "us") {
      if (defined $CONFIG{GRAPH_MAX}) { $CONFIG{GRAPH_MAX}/=1000000; }
      if (defined $CONFIG{GRAPH_MIN}) { $CONFIG{GRAPH_MIN}/=1000000; }
      }
    }

  push @OPTIONS,(
    "-i",                         # graphic interlaced mode
    "-w",$CONFIG{WIDTH},          # drawing area width
    "-h",$CONFIG{HEIGHT},         # drawing area height
    "-b",$CONFIG{GRAPH_UNIT},     # value of "1k" (1000 or 1024)
    "-u",$CONFIG{GRAPH_MAX},      # upper initial border
    "-l",$CONFIG{GRAPH_MIN},      # lower initial border
    "-a",uc($CONFIG{IMAGEFORMAT}) # image format
    );
  return @OPTIONS;
  }


######################################################################
#
# generates an array suitable to feed to RRDs::graph to build a graph
# including a legend with the desired consolidation functions.
#
# Usage:
#   insert_data(type,var,color,description,legends,unit,use_SI);
#
#   type:        AREA LINE1 LINE2 LINE3 STACK
#
#   var:         RRD variable to be graphed and variables which will
#                be assigned to min, average, max and now. They
#                have to be separated by spaces. If less than five
#                variables are stated, the LAST entry will be copied
#                to the remaining positions.
#                If you just want to insert a legend without adding a
#                graph, the first element must be a numerical zero "0" 
#                The "description" can be used for padding the legend.
#
#   color:       graph's color in RRDs::graph notation ( RRGGBB )
#
#   description: name of the graph or short description that will be
#                used in the legend
#
#   legends:     one or more space-separated occurances of:
#                min avg max cur now ("now" is the same as "cur")
#
#   unit:        the unit that will be appended after the last legend
#
#   use_SI:      0 -> just print the plain value
#                1 -> print values in SI units (micro, milli, kilo, mega, ...)
#                -1 -> same as "1", but SI-units will be added without a space
#
# EXAMPLE:
#
#   insert_data("AREA","abc xyz","#0000ff","test legend","min max","bytes",1);
#
#  -> draw a blue area with the rrd variable "abc" and add a corrosponding
#     legend to it, but refer the legend to the variable "xyz". The legend
#     will use SI-units and the unit "bytes". It will look like this:
#
#     [#] test legend (min:   1.23k  max:  12.34M bytes)
#
sub insert_data {
  my $graphtype=shift || "LINE1";
  my $rrdvar=shift || "";
  my $color=shift || "000000";
  my $description=shift || "";
  my $legends=shift || "min avg max";
  my $unit=shift || "";
  my $use_SI_units=shift || 0;
  
  my @legends=split / /,$legends;

  my @vars=split / /,$rrdvar;
  while ($#vars<4) { push @vars,$vars[$#vars]; }

  my $lead="";
  my @array=();
  if ($vars[0] ne "0") { push @array,"$graphtype:$vars[0]#$color:$description"; $description=""; }
  else { $lead="  "; }

  $SI="";
  if ($use_SI_units == 1) { $SI=" %s"; }
  elsif ($use_SI_units == -1) { $SI="%s"; }

  if ($unit ne "") { $unit=" $unit"; }

  my $num=0;
  foreach $legend (@legends) {
    my $open="";
    my $close="";
    if ($num == 0) { $open="$lead$description$lead("; }
    if ($num == $#legends) { $close="$unit)\\n"; }
    $num++;
    if ($legend eq "min") { push @array,"GPRINT:$vars[1]:MIN:$open"."min\\:%7.2lf$SI$close"; }
    elsif ($legend eq "avg") { push @array,"GPRINT:$vars[2]:AVERAGE:$open"."avg\\:%7.2lf$SI$close"; }
    elsif ($legend eq "max") { push @array,"GPRINT:$vars[3]:MAX:$open"."max\\:%7.2lf$SI$close"; }
    elsif ($legend eq "now") { push @array,"GPRINT:$vars[4]:LAST:$open"."now\\:%7.2lf$SI$close"; }
    elsif ($legend eq "cur") { push @array,"GPRINT:$vars[4]:LAST:$open"."now\\:%7.2lf$SI$close"; }
    $description="";
    $lead="";
    }

  return @array;
  }

######################################################################
#
# generates an array suitable to feed to RRDs::graph to build a min/max
# graph including a legend with the desired consolidation functions.
#
# Usage:
#   insert_minmax(var,areacolor,bordercolor,description,unit,use_SI);
#
#   var:         RRD variables to be graphed and assigned to min and max.
#                They have to be separated by spaces.
#                If you just want to insert a legend without adding a
#                graph, the first element must be a numerical zero "0" 
#                The "description" can be used for padding the legend.
#
#   areacolor:   graph area color in RRDs::graph notation ( #RRGGBB )
#
#   bordercolor: border color in RRDs::graph notation ( #RRGGBB )
#
#   description: short description that will be appended in the legend
#
#   unit:        the unit that will be appended after the last legend
#
#   use_SI:      0 -> just print the plain value
#                1 -> print values in SI units (micro, milli, kilo, mega, ...)
#                -1 -> same as "1", but SI-units will be added without a space
#
# EXAMPLE:
#
#   insert_data("AREA","abc xyz","0000ff","test legend","min max","bytes",1);
#
#  -> draw a blue area with the rrd variable "abc" and add a corrosponding
#     legend to it, but refer the legend to the variable "xyz". The legend
#     will use SI-units and the unit "bytes". It will look like this:
#
#     [#] test legend (min:   1.23k  max:  12.34M bytes)
#
sub insert_minmax {
  my $rrdvar=shift || "";
  my $areacolor=shift || "000000";
  my $bordercolor=shift || "";
  my $description=shift || "";
  my $unit=shift || "";
  my $use_SI_units=shift || 0;
  
  my @vars=split / /,$rrdvar;

  my $lead="";
  my @array=();
  if ($vars[0] ne "0") {
    push @array,(
      "CDEF:negmin$vars[0]=$vars[0],0,LT,$vars[0],0,IF",
      "CDEF:negmax$vars[1]=$vars[1],0,LT,$vars[1],0,IF",
      "AREA:$vars[1]#$areacolor:$description",
      "AREA:$vars[0]#FFFFFF:",
      "AREA:negmin$vars[0]#$areacolor:",
      "AREA:negmax$vars[1]#FFFFFF:"
      );
    if ($bordercolor ne "") {
      push @array,(
        "LINE1:$vars[0]#$bordercolor:",
        "LINE1:$vars[1]#$bordercolor:"
        );
      }
    $description="";
    }
  else { $lead="  "; }

  if (! defined $vars[2]) { push @vars,$vars[0]; }
  if (! defined $vars[3]) { push @vars,$vars[1]; }

  $SI="";
  if ($use_SI_units == 1) { $SI=" %s"; }
  elsif ($use_SI_units == -1) { $SI="%s"; }

  if ($unit ne "") { $unit=" $unit"; }

  push @array,(
    "GPRINT:$vars[2]:MIN:$lead$description$lead(min\\:%7.2lf$SI",
    "GPRINT:$vars[2]:MAX:$lead$description$lead/%7.2lf$SI",
    "GPRINT:$vars[3]:MIN:max\\:%7.2lf$SI",
    "GPRINT:$vars[3]:MAX:/%7.2lf$SI$unit)\\n"
    );

  return @array;
  }


######################################################################
#
# generates an array suitable to feed to RRDs::graph to mark
# areas of unknown values
#
# Usage:
#   insert_unknown_area($vars,$color,$description);
#
#   vars:        space separated list of all variables to be taken
#                into account. If one of them is unknown, the area
#                will be marked
#
#   color:       graph's color in RRDs::graph notation ( RRGGBB )
#
#   description: some additional legend that will (if defined) show
#                up in brackets after the string "data unknown".
#
sub insert_unknown_area {
  my $vars=shift;
  my $color=shift || "ffffa0";
  my $description=shift || "";

  if ($description ne "") { $description=" ($description)"; }

  # the scaring ;) definition of "wrongdata":
  # if TIME < now { if x unknown { INF else 0 } else 0 }
  #   CDEF:wrongdata=TIME,$DATE,LT,x,UN,INF,0,IF,0,IF \
  # where "x" is the result of the addition of all variables

  my @vars=split /\s+/,$vars;
  my $string=shift @vars;
  if (@vars) { $string = $string.",".join (",+,",@vars).",+"; }

  return (
    "CDEF:wrongdata=TIME,".time.",LT,$string,UN,INF,0,IF,0,IF",
    "AREA:wrongdata#$color:data unknown$description\\n",
    "CDEF:wrongdatainv=0,wrongdata,-",
    "AREA:wrongdatainv#$color:"
    );
  }


sub insert_lines {
  my %CONFIG=@_;
  my @array=("HRULE:0#000000");
  if (defined $CONFIG{GRAPH_ADDLINE}) {
    foreach (@{$CONFIG{GRAPH_ADDLINE}}) {
      my ($pos,$color,$comment)=split /,/;
      if (defined $CONFIG{$color}) { $color=$CONFIG{$color}; }
      push @array,"HRULE:$pos#$color:$comment"; 
      }
    }
  return @array
  }

sub insert_vars {
  my $dbname=shift;
  my $dbvar=shift;
  my $graphvar=shift;
  my $which=shift;
  my @array=();
  foreach my $consolidation (split /\s+/,$which) {
    my $consname=lc $consolidation;
    if ($consname eq "average") { $consname="avg"; }
    push @array,"DEF:$graphvar"."_"."$consname=$dbname:$dbvar:$consolidation"
    }
  return @array;
  }

1;


Powered by WebSVN 2.2.1