Source Code
packet_report
  Prev   Next
#!/usr/local/bin/perl
#
# vi:tabstop=4
#
#  packet_report                Generate a report from the log of packet throughput
#
# Usage:   packet_count [-d]
#       
# Cron:    55 23 * * *        /usr/local/etc/syswatch/bin/packet_report
#
$OnMac      = ! -e '/etc/passwd';

#
# -------------------- Configurable items -------------------
#

#
# Email addrs of who should receive this msg
#
$NOTIFY = 'matt\@metawire.com hosttrafficdroid\@metawire.com';

#
# Hosts to get daily reports from
#
@HostWithData = (
                    'ptolemy'
                    'dailystop',
                    'comet'
                    'bandit',
                    'bubbles',
                    'marilyn',
                    'buster',
                    'angstrom',
                    'ns2',
                    'ns3',
                    'hpvectra2',
                    'dunsany',
                    'brutus'
                    'miles'
                );

#
# -------------------- Things you MAY need to change -------------------
#

$SW_HOME    = "/usr/local/etc/syswatch"      if( ! $OnMac );
$SCP        = "/usr/local/bin/scp";


#
# -------------------- Everything else should fine ---------------------
#
$SW_HOST    = &read_in_contents_of_file( "$SW_HOME/config/hostname" );
chop( $SW_HOST );

@TheMonthNames = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );

$Today      = &month_day   ( time );
$DayOfMonth = &day_of_month( time );
$TheLogFile = "/var/log/packet_count/day.$DayOfMonth";

$TMP_DIR    ="$SW_HOME/tmp" if( ! $OnMac );
$TMP_FILE   ="$TMP_DIR/packet_report.$$";
$MIN_INIT   = 9999999;


#
# -------------------- Args -------------------
#
$Debug      = $ARGV[ 0 ] eq '-d';


# -------------------- Args -------------------

#
# Mail msg "Subject: " line:
#
$SUBJ       ="Host IP traffic for $Today";


#
# Number of lines in graph (everything is scaled
# to fit this):
#
$N_LINES_OF_GRAPH_DATA  = 22;
$MAX_BAR_WIDTH          = 40;


#
# main
#
    &summarize_data();
    &create_report( $TMP_FILE );
    
    if( $Debug || $OnMac )
    {
        print &read_in_contents_of_file( $TMP_FILE );
    }
    else
    {
        system( "/usr/lib/sendmail $NOTIFY < $TMP_FILE" )
    }
    unlink $TMP_FILE;
    exit;
#
# end
#


sub summarize_data
{
    local ( $host );
    
    foreach $host (@HostWithData)
    {
        if( $host eq $SW_HOST )
        {
            $data_file = $TheLogFile;
        }
        else
        {
            $data_file = &get_remote_log_file( $host );
        }
        
        &read_totals( $host, $data_file );
        
        unlink $data_file if( $host ne $SW_HOST && ! $OnMac );
    }
}


#
# read_totals
#
sub read_totals
{
    local ( $host,
            $log_file ) = @_;
    local ( $hr, $n_secs, $n_sent, $n_rcvd, $n_conn, $ind );
    
    #
    # Don't have a log file? Then we couldn't get
    # it, so don't try to process it
    #
#print "log file = $log_file, does ";
#if( ! -e $log_file )
#{
#  print "NOT ";
#}
#print "exist.\n";
    return if( ! -e $log_file );
    
    #
    # Init vals for this host
    #
    foreach $hr (0..23)
    {
        $ind = "$host $hr";
        $min_hourly_sent{ $ind } = $MIN_INIT;
        $max_hourly_sent{ $ind } = 0;
        $min_hourly_rcvd{ $ind } = $MIN_INIT;
        $max_hourly_rcvd{ $ind } = 0;
        $min_hourly_conn{ $ind } = $MIN_INIT;
        $max_hourly_conn{ $ind } = 0;
    }
    
    #
    # Open and read the log file
    #
    open( LOG, $log_file ) || &fatal_error("Can't open $log_file");
#print "Opened log file ($log_file)\n";
    
    while( <LOG> )
    {
        next if( /^#/ );
        
        #
        # Thu Apr  3 11:16:06 PST 1997  29  524 18  509 17
        #
        #                $hr     n_secs      n_sent      n_rcvd      n_conn
        if( /... ... .. (..):.* ([0-9]*)    ([0-9]*)    ([0-9]*)    ([0-9]*)$/ )
        {
            $hr     = int( $1 );
            $n_secs = $2;
            $n_sent = $3;
            $n_rcvd = $4;
            $n_conn = $5;
            $ind = "$host $hr";
            
            $min_hourly_sent{ $ind } = &min_of( $n_sent, $n_secs, $min_hourly_sent{ $ind } );
            $max_hourly_sent{ $ind } = &max_of( $n_sent, $n_secs, $max_hourly_sent{ $ind } );
            $min_hourly_rcvd{ $ind } = &min_of( $n_rcvd, $n_secs, $min_hourly_rcvd{ $ind } );
            $max_hourly_rcvd{ $ind } = &max_of( $n_rcvd, $n_secs, $max_hourly_rcvd{ $ind } );
            $min_hourly_conn{ $ind } = &min_of( $n_conn, $n_secs, $min_hourly_conn{ $ind } );
            $max_hourly_conn{ $ind } = &max_of( $n_conn, $n_secs, $max_hourly_conn{ $ind } );
            
            $total_sent{ $host } += $n_sent;
#print "$host: hr = $hr, n_sent=$n_sent, n_rcvd=$n_rcvd, n_conn=$n_conn, n_secs=$n_secs\n";
            $total_rcvd{ $host } += $n_rcvd;
            $total_conn{ $host } += $n_conn;
        }
        else
        {
            print STDERR "Badly formed line: $_";
#print "Badly formed line: $_";
            next;
        }
    }
#print "total_sent = " . $total_sent{ $host } . "\n";
    $MaxBarValue = $total_sent{ $host } if( $total_sent{ $host } > $MaxBarValue );
    $MaxBarValue = $total_rcvd{ $host } if( $total_rcvd{ $host } > $MaxBarValue );
    $MaxBarValue = $total_conn{ $host } if( $total_conn{ $host } > $MaxBarValue );
    
    close( LOG );
}


#
# create_report
#
# Putting it in the temp file
#
sub create_report
{
    local ( $report_file ) = @_;
    local ( $host );
    
    open( REPORT, "> $report_file" ) || &fatal_error("Can't open $report_file");
    
    print REPORT "Subject: $SUBJ\n";
    print REPORT  "Total IP packets (TCP + UDP + ICMP) and TCP connections\n\n";
    
    foreach $host (@HostWithData)
    {
        if( $total_rcvd{ $host } == 0 && $total_sent{ $host } == 0 && $total_conn{ $host } == 0 )
        {
            &print_bar_line( $host );
        }
        else
        {
            print REPORT "$host:\n";
            &print_bar_line( '   rcvd:', $total_rcvd{ $host }, "  IP packets" );
            &print_bar_line( '   sent:', $total_sent{ $host }, "  IP packets" );
            &print_bar_line( '   cons:', $total_conn{ $host }, "  (TCP)\n" );
        }
    }
    print REPORT "\n";
    
    print REPORT  "IP packets per second  '.'=min,  max Received, Sent, Connections\n";
    foreach $host (@HostWithData)
    {
        print REPORT "\n\n";
        print REPORT "$host:\n";
        &print_one_host_24_hr_period( $host );
    }
    
    close( REPORT );
}


#
# print_bar_line
#
sub print_bar_line
{
    local ( $beg_label, $n_val, $end_label ) = @_;
    local ( $n_chrs, $i );
    
    print REPORT "$beg_label  ";
    
    if( $n_val == 0 && $end_label eq '' )
    {
        print REPORT "No data\n";
    }
    else
    {
        print REPORT "$what ";
        $n_chrs = int( $n_val * ($MAX_BAR_WIDTH / $MaxBarValue) );
        foreach $i (0..$n_chrs)
        {
            print REPORT "*";
        }
        foreach $i (0..$MAX_BAR_WIDTH - $n_chrs)
        {
            print REPORT ".";
        }
        printf REPORT ("%8d $end_label\n", $n_val );
    }
}


#
# print_one_host_24_hr_period
#
sub print_one_host_24_hr_period
{
    local ( $host ) = @_;
    local ( $ind, $hr, $max_val, $sent_mark, $rcvd_mark, $conn_mark );
    
    foreach $hr (0..23)
    {
        $ind = "$host $hr";
        $min_hourly_sent{ $ind } = 0 if ( $min_hourly_sent{ $ind } == $MIN_INIT );
        $min_hourly_rcvd{ $ind } = 0 if ( $min_hourly_rcvd{ $ind } == $MIN_INIT );
        $min_hourly_conn{ $ind } = 0 if ( $min_hourly_conn{ $ind } == $MIN_INIT );
        $max_val = $max_hourly_sent{ $ind } if( $max_hourly_sent{ $ind } > $max_val );
        $max_val = $max_hourly_rcvd{ $ind } if( $max_hourly_rcvd{ $ind } > $max_val );
        $max_val = $max_hourly_conn{ $ind } if( $max_hourly_conn{ $ind } > $max_val );
    }

    $max_val = $N_LINES_OF_GRAPH_DATA if( $max_val < $N_LINES_OF_GRAPH_DATA );
    
    local ( $scaling ) = $max_val / $N_LINES_OF_GRAPH_DATA;
    
    print REPORT ("-"x78, "|\n" );
    for($line=$N_LINES_OF_GRAPH_DATA; $line > -3; $line--)
    {
        next if( $line == 0 );
        if( $line == -1 )
        {
            print REPORT ("-"x78,"|\n");
            next;
        }
        
        local ( $value_for_this_line ) = $line * $scaling;
        printf REPORT ("%4d| ", int( $value_for_this_line ) ) if( $line > -1 );
        
        print REPORT "hour: " if ( $line == -2 );
        foreach $hr (0..23)
        {
            if( $line == -2 )
            {
                local ( $start ) = $hr;
                $start = "0$hr" if( $hr < 10 );
                print REPORT "$start ";
                next;
            }
            
            $ind = "$host $hr";
            if( $line == 1 && $max_hourly_sent{ $ind } > 0 && $max_hourly_sent{ $ind } < (2 * $scaling) )
            {   $sent_mark = '*';   }
            elsif(    $min_hourly_sent{ $ind } >= $value_for_this_line )
            {   $sent_mark = '.';   }
            elsif( $max_hourly_sent{ $ind } >= $value_for_this_line )
            {   $sent_mark = 's';   }
            else
            {   $sent_mark = ' ';   }
            
            if( $line == 1 && $max_hourly_rcvd{ $ind } > 0 && $max_hourly_rcvd{ $ind } < (2 * $scaling) )
            {   $rcvd_mark = '*';   }
            elsif( $min_hourly_rcvd{ $ind } >= $value_for_this_line )
            {   $rcvd_mark = '.';   }
            elsif( $max_hourly_rcvd{ $ind } >= $value_for_this_line )
            {   $rcvd_mark = 'r';   }
            else
            {   $rcvd_mark = ' ';   }
            
#           if( $line == 1 && $max_hourly_conn{ $ind } > 0 && $max_hourly_conn{ $ind } < (2 * $scaling) )
#           {   $conn_mark = '*';   }
            if( $min_hourly_conn{ $ind } >= $value_for_this_line )
            {   $conn_mark = ':';   }
            elsif( $max_hourly_conn{ $ind } >= $value_for_this_line )
            {   $conn_mark = 'c';   }
            else
            {   $conn_mark = ' ';   }
            
            print REPORT  "$rcvd_mark$sent_mark$conn_mark";
        }
        print REPORT  "|\n";
    }
    print REPORT "-"x78,"|\n";
}


#
# get_remote_log_file
#
# Get the data file from this remote host
#
sub get_remote_log_file
{
    local ( $host ) = @_;
    
    local ( $dst ) = "$TMP_DIR/$host.day.$DayOfMonth";
#   local ( $cmd ) = "$RCP $host:$TheLogFile $dst";
    local ( $cmd ) = "$SCP $host:$TheLogFile $dst";
#   system( "$cmd >& /usr/local/etc/syswatch/tmp/packet-out" );     # if ! $OnMac;
    local ( $xy ) = `$cmd`;
#   print "$cmd = '$xy'\n";
#system( "cat $dst" );
#   print "$cmd\n" if $OnMac;
    
    return $dst;
}



# ------------------ Utils -------------------

sub min_of
{
    local ( $n, $secs, $current_min ) = @_;
    
    local ( $n_per_sec ) = int( $n / $secs );
    $current_min = $n_per_sec if( $n_per_sec < $current_min );
    
    return $current_min;
}


sub max_of
{
    local ( $n, $secs, $current_max ) = @_;
    
    local ( $n_per_sec ) = $n / $secs;
    
    $current_max = $n_per_sec if( $n_per_sec > $current_max );
    
    return $current_max;
}


#
# fatal_error
#
#   Exit with this message. We want to make sure to
#   remove our lock file, so we can run again.
#
sub fatal_error
{
    local ( $msg ) = @_;
    print STDERR "$msg\n";
    exit;
}


#
# read_in_contents_of_file
#
#   Return the contents of this file in a string.
#
sub read_in_contents_of_file
{
    local ( $file_name ) = @_;
    local ( $file_conts );
    
    if( $OnMac )
    {
        open( SRC, $file_name ) || &fatal_error( "Can't open $file_name" );
        
        while( <SRC> )
        {
            $file_conts = $file_conts . $_;
        }
        
        close( SRC );
    }
    else
    {
        $file_conts = `cat $file_name`;
    }
    return $file_conts;
}


#
# month_day()
#
# If time = "Apr 3" rtn "Apr 3"
#
sub month_day
{
    local ( $time_num ) = @_;
    local ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( $time_num );
    
#print "TheMonthNames[ $mon ] = " . $TheMonthNames[ int( $mon ) ] . "\n";
    return "$TheMonthNames[ $mon ] $mday";
}


#
# day_of_month()
#
# Return today's day of the month: if this is Apr 3, rtn "3"
#
sub day_of_month
{
    local ( $time_num ) = @_;
    local ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( $time_num );
    
    $mday = "0$mday" if( int( $mday ) < 10 );
    return "$mday";
}