#!/usr/bin/perl

use Date::Parse;
umask(022);

$TAIL='/bin/tail -6000';
$ZCAT='/opt/local/bin/zcat';
chop($hostnm=`/bin/hostname`);
chop($domain=`/bin/domainname`);
$host="$hostnm.$domain";

$logfilnam='/var/log/cnet/httpd_access_log';
$crickdir='/p/sy/subsys/cricket';
$outprefix='httpd';
$outfilnam="$crickdir/$outprefix.$host";

$KEEPMIN=5;
$KEEPSEC=$KEEPMIN*60;		# count hits in the past 5 minutes
$STALESEC=10*60;		# remove files more than 10 minutes old
$totalhits=0;
$cuhits=0;
$totalbytes=0;
$cubytes=0;
$failhits=0;
$debug='';
$timenow=time();

$nprocs=&wstatus();		# get /server-status

# look for recent entries in the previous log file, if any,
# in case the log file has rotated recently

$foundoldfile='';
if (-r "$logfilnam.1") {	# look for httpd_access_log.1
  if (open(LOG, "$TAIL $logfilnam.1 |")) {
    $r=&read_log();
    print STDERR "$r records parsed in $logfilnam.1\n" if $debug;
    $foundoldfile=1;
  } else {
    print STDERR "can't tail $logfilnam.1: $!\n";
  }
} elsif (-r "$logfilnam.1.gz") { # look for httpd_access_log.1.gz
  if (open(LOG, "$ZCAT $logfilnam.1.gz | $TAIL |")) {
    $r=&read_log();
    print STDERR "$r records parsed in $logfilnam.1.gz\n" if $debug;
    $foundoldfile=1;
  } else {
    print STDERR "can't read $logfilnam.1.gz: $!\n";
  }
}

# parse the last 6000 records of the current log file

die "can't open $logfilnam: $!\n" unless -r $logfilnam;
unless (open(LOG, "$TAIL $logfilnam |")) {
  die "can't tail $logfilnam: $!\n";
}
$r=&read_log();
print STDERR "$r records parsed in $logfilnam\n" if ($debug && $foundoldfile);

exit unless open(OUT, ">$outfilnam");	# die quietly

				# divide all counters by KEEPMIN to get per minute rate
print OUT $totalhits  / $KEEPMIN . "\n";
print OUT $cuhits     / $KEEPMIN . "\n";
print OUT $totalbytes / $KEEPMIN . "\n";
print OUT $cubytes    / $KEEPMIN . "\n";
print OUT $failhits   / $KEEPMIN . "\n";
print OUT "$nprocs\n";
close(OUT);

&remove_stale();		# remove stale files from down hosts


##############################################################################
sub wstatus {			# send http request for server-status
  local($activ)=0;
  local($host)=`/bin/hostname`;
  chop($host);
  local($cmd)="/opt/local/bin/geturl -h $host -u /server-status|";
  return 0 unless open(STA, $cmd);
  while (<STA>) {
    if (/(\d+) requests currently being processed/) {
      $activ=$1;
      $activ-=1;		# don't count this /server-status process
      last;
    }
  }
  close(STA);
  return $activ;
}



sub read_log {
  my($nrecs)=0;
  while (<LOG>) {
    $cudomain='';
    if (/^(\d+\.\d+)\.\d+\.\d+ \S+ \S+ \[(\S+) -\d+\] "\((.+)\)" (\d+) (\d+)/) {
      $network=$1;		# numeric IP address
      $rdate=$2;
      $request=$3;
      $status=$4;
      $bytes=$5;
      $cudomain=1 if $network eq '128.59';
    } elsif (/^\S+\.(\w+\.\w+) \S+ \S+ \[(\S+) -\d+\] "\((.+)\)" (\d+) (\d+)/) {
      $network=$1;		# host name
      $rdate=$2;
      $request=$3;
      $status=$4;
      $bytes=$5;
      if ($network=~/^\d/) {
        print STDERR "parse error: $_" if $debug;;
        next;
      }
      $cudomain=1 if $network eq 'columbia.edu';
    } else {
      next;
    }
    $nrecs++;
    next if $request=~/^GET \/server-status/; # ignore these
    next unless $status=~/^\d+$/; # status must be numeric
    next if (($status >= 300) && ($status < 400)); # ignore redirects

    $rdate=~s/:/ /;		# replace the first colon w space
    $nsecs = $timenow - str2time($rdate);
    next if $nsecs > $KEEPSEC;	# keep records less than 5 min old
  
    if ($status >= 400) {	# failed requests are counted separately
      $failhits++;
      next;
    }
    $totalhits++;
    $cuhits++ if $cudomain;
    $totalbytes+=$bytes;
    $cubytes+=$bytes if $cudomain;
  }  
  close(LOG);
  return $nrecs;
}



sub remove_stale {
  # remove old files created by other hosts which are down now
  die "can't open $crickdir: $!\n" unless opendir(CDIR, $crickdir);
  my($thisfile);
  while ($thisfile=readdir(CDIR)) {
    next unless $thisfile =~ /^$outprefix/;	# only care about httpd files
    my($thispath) = "$crickdir/$thisfile";
    my($mtime) = (stat($thispath))[9];
    next unless $timenow - $mtime > $STALESEC;	# more than 10 minutes old
    if (unlink($thispath)) {
      print STDERR "removed $thispath\n";
    } else {
      print STDERR "unable to remove $thispath: $!\n";
    }
  }
  closedir(CDIR);
}
