#!/usr/local/bin/perl -w ################################################################################ # StatsView data collector # Exit codes: # 0 - OK # 1 - canncelled by interrupt # 2 - argument error # 3 - subprocess error ################################################################################ use strict; use IO::File; use POSIX qw(strftime setsid); use vars qw(%Pids $Verbose); ################################################################################ sub harikari($@) { my ($status, @msg) = @_; print("@msg\n") if (@msg); foreach my $pid (keys(%Pids)) { kill(-15, $pid); waitpid($pid, 0); } exit($status); } ################################################################################ sub writeheader($$) { my ($file, $hdr) = @_; my $fh = IO::File->new($file, "w") || harikari(3, "Can't write to $file: $!"); $fh->print($hdr); $fh->close(); } ################################################################################ sub forkproc($) { my ($cmd) = @_; my $pid; # Parent print("$cmd\n") if ($Verbose); if ($pid = fork()) { $Pids{$pid} = $cmd; return($pid); } # Child elsif (defined($pid)) { setsid(); # So that one signal can be used to kill the entire pipeline exec($cmd) || harikari(3, "Can't exec \"$cmd\": $!"); } # Error else { harikari(3, "Can't fork \"$cmd\": $!"); } } ################################################################################ # Main # Fettle arguments harikari(2, "Insufficient arguments") if (@ARGV < 4); if ($ARGV[0] eq '-v') { $Verbose = 1; shift(@ARGV); } my $output = shift(@ARGV); my $interval = shift(@ARGV); my $count = shift(@ARGV); my %monitors; foreach my $opt (@ARGV) { my ($mon, @args) = split(/[:,]/, $opt); $monitors{$mon} = [ @args ]; } harikari(2, "No monitors specified") if (! keys(%monitors)); # Figure out if mapdev is installed my $mapdev = ""; foreach my $p (split(/:/, $ENV{PATH})) { if (-x "$p/mapdev") { $mapdev = "| mapdev"; last; } } # Trap interrupts $SIG{INT} = sub { harikari(1, "received SIGINT"); }; $SIG{HUP} = sub { harikari(1, "received SIGHUP"); }; $SIG{TERM} = sub { harikari(1, "received SIGTERM"); }; my $hdr = strftime("Start: %d/%m/%y %T Interval: $interval\n\n", localtime()); # sar if (defined($monitors{sar})) { forkproc("sar -A $interval $count $mapdev > $output.sar"); } # iostat if (defined($monitors{iostat})) { writeheader("$output.iostat", $hdr); forkproc("iostat -x $interval $count $mapdev >> $output.iostat"); } # iost+ if (defined($monitors{"iost+"})) { forkproc("iost+ $interval $count > $output.iost+"); } # vmstat if (defined($monitors{vmstat})) { writeheader("$output.vmstat", $hdr); forkproc("vmstat $interval $count >> $output.vmstat"); } # vxstat if (defined($monitors{vxstat}) && ((system("pkginfo -q SUNWvxvm") / 256 == 0) || (system("pkginfo -q VRTSvxvm") / 256 == 0))) { foreach my $dg (@{$monitors{vxstat}}) { forkproc("vxstat -g $dg -i $interval -c $count > $output.vxstat.$dg"); } } # oracle if (defined($monitors{oar}) && (defined($ENV{ORACLE_HOME}) || defined($ENV{TWO_TASK}))) { my ($login, @stats) = @{$monitors{oar}}; forkproc("oar -O $output.oar -L $login -I $interval -C $count @stats"); } # Wait for them all to finish - stop early if any fails while ((my $pid = wait()) != -1) { my $cmd = delete($Pids{$pid}); harikari(3, "\"$cmd\" failed") if ($?); } exit(0); ################################################################################