#!/usr/bin/perl -w # # ======================================================================== # sar2rrd-graph.pl # ------------------------------------------------------------------------ # # This script can be used to parse sar command output. # It will create RRDTool archives and graphs. # # You can use command line arguments to select the graphs # and the columns you wish. # # Common bug: lines of input text must end by '\n' not '\r\n' ! # # ------------------------------------------------------------------------ # Author: Jerome Delamarche (jd@maje.biz - jd@trickytools.com) # Version: 2.4 # Date: 21 Feb 2009 # ======================================================================== # use strict; use Getopt::Std; use Time::Local; use Date::Calc qw(Add_Delta_Days); use XML::Simple; # Global parameters: my $gRRDTool = "/usr/local/rrdtool/bin/rrdtool"; # Parameters overridable via the command line: my $uVerbose = 0; my $uContinueOnErrors = 0; my $uStartDate = ""; my $uEndDate = ""; my $uPeriod = ""; my $uStep = ""; my $uXMLSpec = ""; my $uImgHeight = 0; my $uImgWidth = 0; my $uLogarithmic = ""; # Graph parameters: my $gGraphStartSec = 0; my $gGraphEndSec = 0; my $gTitle = ""; my $gVlabel = ""; my $gRRDName = ""; my $gImgName = ""; my $gDefs = ""; # --------------------------------------------------------------------- # Command line analysis: # --------------------------------------------------------------------- my %opts = (); getopts("?coH:W:vS:e:s:x:p:",\%opts); if (exists($opts{'?'})) { Usage(); } if (exists($opts{'c'})) { $uContinueOnErrors = 1; } if (exists($opts{'H'})) { $uImgHeight = $opts{'H'}; } if (exists($opts{'W'})) { $uImgWidth = $opts{'W'}; } if (exists($opts{'o'})) { $uLogarithmic = "-o"; } if (exists($opts{'s'})) { $uStartDate = $opts{'s'}; } if (exists($opts{'e'})) { $uEndDate = $opts{'e'}; } if (exists($opts{'S'})) { $uStep = $opts{'S'}; } if (exists($opts{'x'})) { $uXMLSpec = $opts{'x'}; } if (exists($opts{'p'})) { $uPeriod = $opts{'p'}; } if (exists($opts{'v'})) { $uVerbose = 1; } # Parameters check: # should specify multiple files ? a hostname ? a range ? data to process ? die("'$gRRDTool' is not an executable") if ! -x $gRRDTool; die("The XML Graph Specification is missing (option -x)") if $uXMLSpec eq ""; die("The XML Graph Specification '$uXMLSpec' is not readable") if ! -r $uXMLSpec; if ($uPeriod ne "" && ($uStartDate ne "" || $uEndDate ne "")) { die("The '-p' option is exclusive with the '-s' and '-e' options"); } if ($uPeriod ne "") { if ($uPeriod ne "lastday" && $uPeriod ne "lastweek" && $uPeriod ne "lastmonth" && $uPeriod ne "lastyear") { die("The value for parameter '-p' is invalid - must be lastday, lastweek, lastmonth or lastyear"); } } # Read XML Spec content: my $xmlcontent = XMLin($uXMLSpec); if ($uImgHeight == 0) { $uImgHeight = $xmlcontent->{height}; } if ($uImgWidth == 0) { $uImgWidth = $xmlcontent->{width}; } if ($uLogarithmic eq "") { $uLogarithmic = $xmlcontent->{logarithmic}; if (ref($uLogarithmic) eq "HASH") { $uLogarithmic = ""; } } $gVlabel = $xmlcontent->{vlabel}; $gTitle = $xmlcontent->{title}; $gRRDName = $xmlcontent->{rrdfile}; if ($uStep eq "") { $uStep = $xmlcontent->{deltasec}; } $gImgName = $xmlcontent->{imgfile}; $gDefs = $xmlcontent->{defs}; # Added with v1.2: # Try to determine RRDTool version, because the syntax for the legend has changed between the versions: my $version = `$gRRDTool | grep Copyright`; my $dummy; ($dummy,$version) = split(/ /,$version); my @vparts = split(/\./,$version); my $gSpecialColon = 1; if ($vparts[0] < 1 || ($vparts[0] == 1 && $vparts[1] < 2)) { $gSpecialColon = 0; } # Compute the start and end date: my $startdate; my $enddate; my $legend; my $cmd; if ($uPeriod ne "") { $cmd = "$gRRDTool last $gRRDName"; $uEndDate = `$cmd`; chomp $uEndDate; if ($uEndDate < 0) { die("'$gRRDTool last $gRRDName' failed"); } if ($uPeriod eq "lastday") { $uStartDate = $uEndDate - 3600 * 24; $legend = 'Last Day'; } elsif ($uPeriod eq "lastweek") { $uStartDate = $uEndDate - 3600 * 24 * 7; $legend = 'Last Week'; } elsif ($uPeriod eq "lastmonth") { $uStartDate = $uEndDate - 3600 * 24 * 30; $legend = 'Last Month'; } elsif ($uPeriod eq "lastyear") { $uStartDate = $uEndDate - 3600 * 24 * 365; $legend = 'Last Year'; } $legend = '"COMMENT:'.$legend.'\\c" "COMMENT:\\n"'; } else { if ($uStartDate eq "") { my $cmd = "$gRRDTool first $gRRDName"; $uStartDate = `$cmd`; chomp $uStartDate; if ($uStartDate < 0) { die("'$gRRDTool first $gRRDName' failed"); } } if ($uEndDate eq "") { $cmd = "$gRRDTool last $gRRDName"; $uEndDate = `$cmd`; chomp $uEndDate; if ($uEndDate < 0) { die("'$gRRDTool last $gRRDName' failed"); } } $startdate = localtime($uStartDate); $enddate = localtime($uEndDate); if ($gSpecialColon) { $startdate =~ s/:/\\:/g; $enddate =~ s/:/\\:/g; } $legend = '"COMMENT:From '.$startdate.', To '.$enddate.'\\c" "COMMENT:\\n"'; } $cmd = "$gRRDTool graph $gImgName -t '$gTitle' -s $uStartDate -e $uEndDate $uLogarithmic -S $uStep -v '$gVlabel' -w $uImgWidth -h $uImgHeight -a PNG $legend $gDefs >/dev/null"; MySystem($cmd); sub MySystem { my ($cmd) = @_; my $status; if ($uVerbose) { print $cmd,"\n"; } if ($status = system($cmd)) { if (!$uContinueOnErrors) { die("Command '$cmd' failed with return code: $status\n"); } } } sub Usage { print "Usage: $0\t[-?ovc] [-W width] [-H height]\n"; print "\t\t\t[-s start_date] [-e end_date] [-S step]\n"; print "\t\t\t[-p lastday|lastweek|lastmonth|lastyear] -x XMLSpec\n"; print "Options:\n"; print "\t-? : this help\n"; print "\t-v : verbose mode\n"; print "\t-c : continue on error\n"; print "\t-o : use a logarithmic scale for Y scale\n"; print "\t-W width : images width (in pixels)\n"; print "\t-H height : images height (in pixels)\n"; print "\t-s start_date : start date (MM-DD-YYYY HH:MM:SS)\n"; print "\t-e end_date : end date (MM-DD-YYYY HH:MM:SS)\n"; print "\t-S step : interval (in seconds) between to values in the graph\n"; print "\t-p period : exclusive with -s and -e\n"; print "\t-x XMLFileSpec : name of XML file which describes the graph to generate\n"; exit(1); } exit(0); # EOF