#!/usr/bin/perl -w # # watchtokens.pl, v0.34, 2/11/2005 # # little script to watch for available tokens # Risto Kotalampi, risto@kotalampi.com # # Enhancements: # 1) Modify evals to check that variable names are correct # use Sys::Syslog; use Getopt::Long; # just initialize bunch of variables $b1 = 0; $b2 = 0; $b3 = 0; $b4 = 0; $b5 = 0; $lproblem = 0; $maxload = 3.0; $minload = 1.1; $lines = 0; $token_refill = 0; $io_rate = 0; $io_tokens = 0; $token_max = 0; $delta = 0; $io_tokens_prev = 0; $startfile ="/etc/rc.d/start.sh"; $stopfile ="/etc/rc.d/stop.sh"; $sleep = 15; $filebase = "/var/adm/watchtokens"; $l = 0.2; $u = 0.5; $problem = 0; $ok = 1; $file_prev = ""; GetOptions("sleep=i", "stop=s", "low=i", "high=i", "startfile=s", "stopfile=s") || die "Wrong option! See the help\n"; if($opt_startfile){ $startfile = $opt_startfile; } if($opt_stopfile){ $stopfile = $opt_stopfile; } if($opt_sleep){ $sleep = $opt_sleep; } if($opt_low){ $l = $opt_low/100; } if($opt_high){ $u = $opt_high/100; } if(!stat("/proc/loadavg") || !stat("/proc/io_status")){ print STDERR "kernel not compatible\n"; exit(-1); } while ($ok){ $action = "x"; if($lproblem){ $action = "L"; } if($problem){ $action = "P"; } ($sec,$min,$hr,$mday,$mon,$year) = localtime(); $year += 1900; $mon++; $file = "$filebase.$mon-$mday-$year.log"; # open the logfile if date has changed or we don't have it open yet if(($file ne $file_prev) && !$fileopen){ open(FILE, ">>$file"); $fileopen = 1; } # close the old logfile and open new if the date has changed if(($file ne $file_prev) && $fileopen){ close(FILE); open(FILE, ">>$file"); $fileopen = 1; } $file_prev = $file; # just pad times to be two digit if($sec < 10){ $sec = "0$sec"; } if($min < 10){ $min = "0$min"; } if($hr < 10){ $hr = "0$hr"; } $date = "$hr:$min:$sec"; # get the critical data $load = `cat /proc/loadavg`; $out = `cat /proc/io_status`; # chomping is fun chomp($out); chomp($load); ($b1, $b2, $b3, $b4, $b5) = split(' ', $load); $l1 = $b1; # print STDERR "$l1\n"; # exit(0); # get the variables from data if($out =~ /^(io_count=)(\d+)(\s+)(io_rate=)(\d+)(\s+)(io_tokens=)(\d+)(\s+)(token_refill=)(\d+)(\s+)(token_max=)(\d+)$/){ $io_rate = $5; $io_tokens = $8; $token_refill = $11; $token_max = $14; } else { print STDERR "Invalid /proc/io_status syntax\n"; exit(-1); } # this tells if we're going up or down. Positive good, negative bad. $rate = $token_refill - $io_rate ; # I want to know how much we have changed $delta = $io_tokens - $io_tokens_prev; $io_tokens_prev = $io_tokens; $timeleft = 0; # predict the time it will take to hit zero if($rate < 0){ $timeleft = $io_tokens/(-$rate); $marker = "-"; } # predict the time it will take to reach token_max again if ($rate > 0){ $diff = $token_max - $io_tokens; $timeleft = $diff/$rate; $marker = "+"; } $timeleft = abs($timeleft); $timeleft = int($timeleft); $timeleft = "$marker$timeleft"; if($marker eq "+"){ $timel1 = "0"; $timel2 = abs($timeleft); } if($marker eq "-"){ $timel1 = abs($timeleft); $timel2 = "0"; } # let's fix the limits $llimit = $token_max * $l; $ulimit = $token_max * $u; # let's see in percents where we are $fillrate = int(100*($io_tokens/$token_max)); # headers are cool $hstring = sprintf ("%8s %2s %5s %10s %7s %7s %7s %7s %10s %7s", "Time", "A", "%", "io_tokens", "delta", "rate", "io_rate", "TTL", "Wait", "Load"); # ... especially every 20 lines (a la vmstat) if($lines % 20 == 0) { print FILE "$hstring\n"; } # problems! if(($l1 > $maxload) && !$problem && !$lproblem){ if($opt_stop){ stop_services(); } $lproblem = 1; } if($lproblem && ($l1 < $minload)){ if($opt_stop){ start_services(); } $lproblem = 0; } if((($io_tokens < $llimit) && !$lproblem && !$problem)){ # print FILE "Problem detected\n"; if($opt_stop){ stop_services(); } $problem = 1; } # all clear if(($io_tokens > $ulimit) && ($problem)){ # print FILE "Problem cleared\n"; if($opt_stop){ start_services(); } $problem = 0; } # let's spit it out $string = sprintf ("%8s %2s %5d %10d %7d %7s %7d %7d %10d %7s", $date, $action, $fillrate, $io_tokens, $delta, $rate, $io_rate, $timel1, $timel2, $l1); if($lines){ print FILE "$string\n"; } $lines++; sleep($sleep); } # functions sub stop_services { system("sh $stopfile"); openlog('watchtokens.pl', 'cons,pid', 'user'); syslog('mail|info', "watchtokens.pl stopped services"); $action = "-"; closelog(); } sub start_services { system("sh $startfile"); openlog('watchtokens.pl', 'cons,pid', 'user'); syslog('mail|info', "watchtokens.pl started services"); $action = "+"; closelog(); }