#!/usr/bin/perl -w
#
###
# Project: pflogstats
# Program: rsyncstats.pl
# Description: Main program for extract accounting information from rsync log file
#
# Copyright (C) 2003-2003 by Dr. Peter Bieringer <pbieringer at aerasec dot de>
# ftp://ftp.aerasec.de/pub/linux/postfix/pflogsumm/
#
# License: GNU GPL v2
# CVS: $Id: rsyncstats.pl,v 1.1 2003/10/20 13:14:37 rootadm Exp $
#
# See also following files: LICENSE, ChangeLog
###
###
# ChangeLog
# 0.01
# - copy from apachelogiostats.pl and adapt it
###
# ToDo
# - timerange (set)
# - implement "format"
###
use strict;
use Getopt::Long;
## Name and version
use vars qw{$release $progName};
$release = "0.01";
$progName = "rsyncstats.pl";
## Define global variables
# option handling
use vars qw{%options %opts};
$options{'help|h|?'} = \$opts{'help'};
$options{"version"} = \$opts{'version'};
# module hooks
use vars qw{%hooks};
# Number formats
use vars qw{%numberformat};
## Module loader
# 1st: look into current directory
push @INC, ".";
# 2nd: look into /usr/local/lib/pflogstats
push @INC, "/usr/local/lib/pflogstats";
# 3rd: look into /usr/lib/pflogstats
push @INC, "/usr/lib/pflogstats";
# General
require "pflogstats-common-support.pm";
require "pflogstats-extensions-networking.pm";
## Print options (debug)
#for my $key (keys %options) {
# print $key . "\n";
#};
#exit 0;
# Local variables
my %accounting;
$accounting{'sent'} += 0;
$accounting{'rcvd'} += 0;
my @mainhelptext;
my $p_hook;
# Time range of logdata
use vars qw{$timemin $timemax};
my ($time);
# Local functions prototyping
sub print_rsync_stats();
## Help function
sub print_help() {
print "$progName $release\n\n";
print STDERR " Options from included modules:\n\n";
## Hook 'help'
for my $p_hook (sort keys %{$hooks{'help'}}) {
my $helpstring = &{$hooks{'help'}->{$p_hook}};
print STDERR " Options from module '" . $p_hook . "':";
print STDERR $helpstring . "\n";
};
};
## Hook 'early_begin'
for my $p_hook (keys %{$hooks{'early_begin'}}) {
&{$hooks{'early_begin'}->{$p_hook}};
};
## Get options
my $ret = GetOptions(%options);
if (! $ret ) {
print_help();
exit 1;
};
# Print help or version
if(defined($opts{'help'})) {
print_help();
exit 0;
};
if(defined($opts{'version'})) {
print "$progName $release\n";
exit 0;
};
## Hook 'checkoptions'
for $p_hook (keys %{$hooks{'checkoptions'}}) {
&{$hooks{'checkoptions'}->{$p_hook}};
};
## Hook 'beforemainloopstarts'
for $p_hook (keys %{$hooks{'beforemainloopstarts'}}) {
&{$hooks{'beforemainloopstarts'}->{$p_hook}};
};
print "DEBUG: start parsing logfile\n" if ($opts{'debug'});
## Start parsing logfile #################################################
my $skip;
my ($pid, $ip, $rcvd, $sent, $date, $direction);
my %tracker;
while(<>) {
chomp;
$_ =~ s/^M$//g; # Remove trailing CR
$~ =~ s/^[[:space:][:cntrl:]]+$//g; # Remove spaces and ctrl chars only
next if (length($_) == 0); # skip empty lines
# Parsing rsync log
# Todo: Datematching!!!!
undef $pid; undef $ip; undef $rcvd; undef $sent; undef $date; undef $direction;
# Loglines:
# PID tracking for network:
# 2003/10/01 05:00:01 [7831] rsync on server-rsync from client.domain.example (1.2.3.4)
# Accounting line:
# 2003/10/01 05:00:02 [7831] wrote 3914 bytes read 121 bytes total size 669824
printf STDERR "DEBUG/rsync: line='" . $_ . "'\n" if ( $opts{'debug'} & 0x0040 );
if ( /rsync: name lookup failed for /i ) {
next;
} elsif ( /rsync: forward name lookup for /i ) {
next;
} elsif ( /rsync: read error: /i ) {
next;
} elsif ( /rsync error: error in rsync protocol data stream /i ) {
next;
} elsif ( /max connections/i ) {
next;
} elsif ( ($date, $pid, $direction, $ip) = /^(\S+ \S+)\s+\[(\d+)\] rsync (on|to) .* from .*\s+\((\S+)\)$/ ) {
# Get PID tracking line
printf STDERR "DEBUG/rsync: ip='" . $ip . "' pid='" . $pid . "' date='" . $date . "'\n" if ( $opts{'debug'} & 0x0020 );
if (defined $tracker{$pid}) {
die "ERROR/rsync: pid duplication: " . $_;
};
# Fill information into tracker
$tracker{$pid}->{'ip'} = $ip;
$tracker{$pid}->{'date'} = $date;
#$tracker{$pid}->{'direction'} = $direction;
} elsif ( ($date, $pid, $sent, $rcvd) = /^(\S+ \S+)\s+\[(\d+)\] wrote (\d+) bytes\s+read (\d+) bytes.*$/ ) {
# Get Accouting line
$skip = 0;
# Look for tracker information given
if (defined $tracker{$pid}) {
$ip = $tracker{$pid}->{'ip'};
$date = $tracker{$pid}->{'date'};
# Remove tracker entry
undef $tracker{$pid};
# Hook "testipaddress"
for my $p_hook (keys %{$main::hooks{'testipaddress'}}) {
if ( &{$main::hooks{'testipaddress'}->{$p_hook}} ($ip) != 0 ) {
# excluded
printf STDERR "DEBUG/rsync: excluded from accounting\n" if ($opts{'debug'} & 0x0010 ) ;
$skip = 1;
last;
};
};
} else {
# No tracker information, account always
# Happen on direction: to
};
# Calculate Unixtime
if (! ($date =~ /^(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)$/)) {
print STDERR "ERROR/rsync: line contains no valid date: $date\n";
};
$time = timelocal( $6, $5, $4, $3, $2, $1);
# Catch min/max times for late timerange display
if (! defined $timemin || ! defined $timemax ) {
# initial values
if (! defined $timemin) { $timemin = $time };
if (! defined $timemax) { $timemax = $time };
} else {
# get min/max
if ($time < $timemin) { $timemin = $time; }
elsif ($time > $timemax) { $timemax = $time; };
};
if ($skip == 0) {
$accounting{'sent'} += $sent;
$accounting{'rcvd'} += $rcvd;
};
} else {
die "WARN/rsync: unrecognized log line: " . $_;
};
};
print "DEBUG/rsync: end parsing logfile\n" if ($opts{'debug'});
&print_rsync_stats();
exit 0;
#### END
# statistics
sub print_rsync_stats() {
print_headline("rsync logio accounting statistics", "default");
print '='x75 . "\n";
printf "%-50s: %6s\n", "", "BytesTraffic";
print_timerange_normal();
print '-'x75 . "\n";
printf "%-50s: %9d %9s\n",
"received (requests)",
$accounting{'rcvd'},
$numberformat{$opts{'numberformat'}}->format_bytes($accounting{'rcvd'});
printf "%-50s: %9d %9s\n",
"sent (data)",
$accounting{'sent'},
$numberformat{$opts{'numberformat'}}->format_bytes($accounting{'sent'});
print '-'x75 . "\n";
printf "%-50s: %9d %9s\n", "Total",
$accounting{'rcvd'} + $accounting{'sent'},
$numberformat{$opts{'numberformat'}}->format_bytes($accounting{'rcvd'} + $accounting{'sent'});
print '='x75 . "\n";
print "\n";
return 0;
};
syntax highlighted by Code2HTML, v. 0.9.1