#!/usr/bin/perl -w package HotSaNIC::squid; use strict; use File::stat; use Data::Dumper; use Carp; sub new { my $self = shift; my $settings = shift; # Open the settings, slurp into hash. my %settings; open ( FILE , $settings ) || croak "Cant open settings, $settings $!"; while () { # throwout comments/blanks next if ($_ =~ /^#/); next if ($_ =~/^\s+$/); chomp; my ($var, $val); ($var , $val ) = split '=' , $_; $settings{$var}=$val; } $settings{TIME}=time; return bless {%settings}, $self; } # Open a file to read persistant data # recollect returns the offset from BOF for seek (where) # and the inode number of the log when we saw it last. sub recollect { my $self = shift; my ($where , $node, $data); open ( F , '<.p' ) || return (0,0); $data = scalar ; close F; $data =~ /(\d+):(\d+)/; $where = $1;$node = $2; print "Recollected $where , $node\n"; return ($where, $node); } # Write info back to persistant file. sub remember { my $self = shift; my ($where , $node) = @_; open ( F , '>.p' ) || croak "Cant open persisting file"; print F "$where:$node"; close F; } sub go { my $self = shift; my ( $where , $node , $logstat, $pos); my ( $time , $duration , $result , $bytes); ($where , $node ) = $self->recollect; $logstat = stat ($self->{LOG}); # Compare atime of log agains the persistant info. if ( $node != $logstat->ino ) { # Oops, the log has been rotated since we last ran print "Oh crap , someone spun the log beneath us!\n"; $self->remember(0, $logstat->ino ); $where = 0; } # Fiddle through the log open ( LOG , $self->{LOG} ) || croak "Cannot open log ,$!"; seek LOG , $where ,0; $self->{POS} = tell LOG; $self->{DURATIONMIN}=999999; # A very big bogus number $self->{DURATIONMAX}=0; $self->{BYTESHIT}=0; $self->{BYTESMISS}=0; $self->{GROSSREQUESTS}=0; while ( ) { if ($self->inInterval($_)) { # DO Something with this VALUABLE information # Moreover , set $self{POS} to mark position in file. #print "$_"; $self->{POS}= tell LOG; ($time , $duration , $result , $bytes , undef) = $self->breakLine($_); # Tally up some figures if ($result =~ /HIT/) { $self->{BYTESHIT} += $bytes }; if ($result =~ /MISS/) { $self->{BYTESMISS} += $bytes }; if ($duration > $self->{DURATIONMAX}) { $self->{DURATIONMAX} = $duration }; $self->{GROSSREQUESTS}++; if ($duration < $self->{DURATIONMIN}) { $self->{DURATIONMIN} = $duration }; } } if ($self->{DURATIONMIN} == 999999) { $self->{DURATIONMIN}='U'}; if ($self->{DURATIONMAX} == 0) { $self->{DURATIONMAX}='U' }; $self->remember( $self->{POS} , $logstat->ino ); print Dumper $self; } sub breakLine { # Splitter for squid access logs my $self = shift; my $line = shift; my @data = split " ", $line; splice @data , 2 ,1; return @data; } sub inInterval { # determine if the passed line is in our interval range. my $self = shift; my $line = shift; $line =~ /^(\d+\.\d+)\s+/; my $time = $1; ($time < $self->{TIME} ) and ($time > ($self->{TIME}-60) ) and return $line; return undef } package main; use File::stat; my $zz= HotSaNIC::squid->new('settings'); $zz->go;