#! /bin/perl

# Copyright (c) 1996 University of Cambridge.
# See the file NOTICE for conditions of use and distribution.


# Perl script to generate statistics from one or more Exim log files.
# This is currently very rudimentary, and could do with a lot more
# polishing.

# Usage: eximstats <log file> <log file> ...

# Features still needed to be added:
#
#  (1) Invent some options, for example, the topcount setting and possible
#      others.
#
#  (2) Consider some stats about lengths of time spend on the queue.

# 1996-05-21: Ignore lines not starting with valid date/time, just in case
#             these get into a log file.



##################################################
#                   Subroutines                  #
##################################################

sub print_volume_rounded {
local($x) = pop @_;
if ($x < 10000)
  {
  printf("%6d", $x);
  }
elsif ($x < 10000000)
  {
  printf("%4dKb", ($x + 512)/1024);
  }
else 
  {
  printf("%4dMb", ($x + 512*1024)/(1024*1024));
  } 
}    



##################################################
#                 Main Program                   #
##################################################

$topcount = 50;
$begin = "9999-99-99 99:99:99";
$end = "0000-00-00 00:00:00"; 

# Scan the input files and collect the data

while (<>)
  {
  next if ! /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}/;
  $tod = substr($_, 0, 19);
  $begin = $tod if $tod lt $begin;
  $end = $tod if $tod gt $end;   
 
  $flag = substr($_, 37, 2); 
  if ($flag eq "<=")
    {
    ($id) = /.{19}(.{16})/;
    ($thissize) = /S=(\S+)/; 
    ($host) = /H=(\S+)/;
    $host = "local" if "$host" eq "";
    $size{$id} = $thissize;
    $received_count{$host}++;
    $received_data{$host} += $thissize;
    $received_count_total++;  
    $received_data_total += $thissize; 
    }  
  elsif ($flag eq "=>")
    { 
    ($id) = /.{19}(.{16})/;
    ($host) = /H=(\S+)/;
    ($transport) = /T=(\S+)/; 
    $size = $size{$id}; 
    $host = "local" if "$host" eq "";
    $delivered_count{$host}++;
    $delivered_data{$host} += $size; 
    $delivered_count_total++;
    $delivered_data_total += $size;  
    $transported_data{$transport} += $size; 
    $transported_count{$transport}++; 

    ($hour) = $tod =~ /^\S+ ([0-9]{2}):/;
    $hour_count[$hour]++;
    } 
  elsif ($flag eq "**")
    {
    ($error) = substr($_, 40);
    $errors_count{$error}++;  
    }     
  }

print "\nExim statistics from $begin to $end\n";

# Print grand totals

print "\n    TOTAL               Volume    Messages    Hosts";
print "\n    Received            ";
&print_volume_rounded($received_data_total);
printf("      %6d     %4d", $received_count_total, 
  scalar(keys %received_data));

print "\n    Delivered           ";
&print_volume_rounded($delivered_data_total);
printf("      %6d     %4d\n", $delivered_count_total, 
  scalar(keys %delivered_data));
 
# Print totals by transport

print "\nDeliveries by transport\n";
print "\n                        Volume    Messages";

foreach $key (sort keys %transported_data)
  {
  printf( "\n    %-16s  %8d        %4d", $key, $transported_data{$key},
    $transported_count{$key});  
  } 
  
# Print the deliveries per hour as a histogram. First find the maximum
# in one hour and scale accordingly.

$maxd = 0;
for ($i = 0; $i < 24; $i++) 
  { $maxd = $hour_count[$i] if $hour_count[$i] > $maxd; }

$scale = int(($maxd + 25)/50);
$scale = 1 if $scale == 0;

printf("\n\nDeliveries per hour (each dot is $scale deliver%s)\n\n",
  ($scale == 1)? "y" : "ies");

for ($i = 0; $i < 24; $i++)
  {
  $c = $hour_count[$i]; 
  printf("%02d-%02d %6d ", $i, $i + 1, $c);
  for ($j = 1; $j <= $c/$scale; $j++)
    {
    printf(".");
    }
  printf("\n");        
  } 

# Print the big senders
  
print "\n\nTop $topcount senders by message count\n\n";
$count = 1;
foreach $key (sort 
               {
               $received_count{$b} <=> $received_count{$a} ||
               $received_data{$b}  <=> $received_data{$a}  ||
               $a cmp $b  
               } 
             keys %received_count)
  {
  printf("%5d %8d   %s\n", $received_count{$key}, $received_data{$key}, $key);
  last if $count++ >= $topcount; 
  }
  
print "\nTop $topcount senders by volume\n\n";
$count = 1;
foreach $key (sort
               {
               $received_data{$b}  <=> $received_data{$a}  ||
               $received_count{$b} <=> $received_count{$a} ||
               $a cmp $b  
               } 
             keys %received_count)
  {
  printf("%5d %8d   %s\n", $received_count{$key}, $received_data{$key}, $key);
  last if $count++ >= $topcount; 
  }

# Print the big receivers
  
print "\nTop $topcount destinations by message count\n\n";
$count = 1;
foreach $key (sort
               {
               $delivered_count{$b} <=> $delivered_count{$a} ||
               $delivered_data{$b}  <=> $delivered_data{$a}  ||
               $a cmp $b  
               } 
             keys %delivered_count)
  {                          
  printf("%5d %8d   %s\n", $delivered_count{$key}, $delivered_data{$key}, $key);
  last if $count++ >= $topcount; 
  }
  
print "\nTop $topcount destinations by volume\n\n";
$count = 1;
foreach $key (sort
               {
               $delivered_data{$b}  <=> $delivered_data{$a}  ||
               $delivered_count{$b} <=> $delivered_count{$a} ||
               $a cmp $b  
               } 
             keys %delivered_count)
  {
  printf("%5d %8d   %s\n", $delivered_count{$key}, $delivered_data{$key}, $key);
  last if $count++ >= $topcount; 
  }

if (scalar(keys %errors_count) == 0)
  {
  printf "\nNo errors\n";
  }

else
  {     
  print "\nErrors\n\n";
  
  foreach $key (sort keys %errors_count)
    {
    chop($text = $key); 
    printf("%5d ", $errors_count{$key});
    while (length($text) > 65)
      {
      ($first,$rest) = $text =~ /(.{55}\S*)\s+(.+)/;
      if (!$first)
        {
        printf("%s\n", $text);
        last; 
        }  
      printf("%s\n      ", $first);
      $text = $rest; 
      }  
    printf("%s\n", $text);  
    }  
  }   

print "\n";  

# End of eximstats  
