#!/usr/local/bin/perl

# $Id: gps4a.pl,v 1.9 1998/03/01 16:26:12 elkner Exp $
# GetProxyStats for Analysis
# Written by Jens Elkner  elkner@irb.cs.uni-magdeburg.de (August 1997)

# Documentation: http://ivs.cs.uni-magdeburg.de/~elkner/webtools/pcm.shtml

# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS 
# OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE 
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
# PARTICULAR PURPOSE.
#
# I offer it to the public domain and I ask, however, that this paragraph
# and my name be retained in any modified versions of the file you may
# make, and that you notify me of any improvements you make to the code.
#
# Use of this software in any way or in any form, source or binary,
# is not allowed in any country which prohibits disclaimers of any 
# implied warranties of merchantability or fitness for a particular
# purpose or any disclaimers of a similar nature.
#
# IN NO EVENT SHALL I BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 
# SPECIAL, INCIDENTAL,  OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 
# USE OF THIS SOFTWARE AND ITS DOCUMENTATION (INCLUDING, BUT NOT 
# LIMITED TO, LOST PROFITS) EVEN IF I HAVE BEEN ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE

# LM: 98/03/01  lock file for each mrtg process (in case mrtg runs longer 
#               than the period between gps4a.pl is called; data will be
#               collected as usual)
# LM: 98/02/16  mrtg 2.5.1 adaption: more and more features become bugs
#               - doesn't  accept floating point numbers any more :(( 
#               -> data for MRTG LRU, select are rounded and
#               - mrtg.conf: memory, rss are converted to Bytes
#                            swap problem (GB = overflow ...) 
# LM: 98/02/05  use a config file for getting variable settings
# LM: 97/08/19  first non-beta :)

use Getopt::Std;
use strict;
use Socket;
use Date::Parse;
use Cwd;

my($debug)=0;
my($mrtg)="";
my($cfgfile)=".grc";
my($datadir)="";
my($mrtgdir)="";
my($icondir)="/icons/mrtg/";
my($testurl)="";
my($echoping)="";
my(%cache)=();
my(%port)=();
my(%passwd)=();
my($Version)="GPS4A 2.0";
my(%result) = ();
my($key,$obj) = 0;
my($forcecreate) = "";
my($lockfile) = ".lock";

# Actually we only need info, dns, utilization and echoping for
# getting the required data. If you want data from other cachemgr objects,
# you may comment them out, but you have to write your own code snipplet
# for parsing the obtained data (see sub HandleResults)

my(@object) = (
	       "info",
#	       "squid.conf",
#	       "server_list",
#	       "client_list",
#	       "log",
#	       "parameter",
#	       "stats/ipcache",
#	       "stats/fqdncache",
	       "stats/dns",
#	       "stats/redirector",
#	       "stats/objects",
#	       "stats/vm_objects",
	       "stats/utilization",
#	       "stats/io",
#	       "stats/reply_headers",
#	       "stats/filedescriptors",
#	       "stats/netdb",
#	       "shutdown",
#	       "refresh",
#	       "remove",
	       "echoping"            # actually this isn't a cache object ;-)
		);		

&GetOptions;
&ReadRcFile;
&GetData;
&DoMrtg if (! $forcecreate);

# --------- End of Main --------------------------------

sub ReadRcFile {
    my($key,$ip,$p,$pw);
    if (! open(RC,$cfgfile) ) {
	warn("Can't open configuration file $cfgfile\nExiting.\n");
	exit(2);
    }
    while (<RC>) {
	s/^\s+(.*)\s+$/$1/;
	s/\s*#.*//;
	next if /^$/;
	print "cfg file: $_" if $debug;
	chop;
	if ( /^htmldir\s*=/ ) {
	    $mrtgdir = $_;
	    $mrtgdir =~ s/^[^=]+=\s*//;
	    print "htmldir = $mrtgdir\n" if $debug;
	}
	if ( /^datadir\s*=/ ) {
	    $datadir = $_;
	    $datadir =~ s/^[^=]+=\s*//;
	    print "datadir = $datadir\n" if $debug;
	}
	if ( /^mrtg\s*=/ ) {
	    $mrtg = $_;
	    $mrtg =~ s/^[^=]+=\s*//;
	    print "mrtg = $mrtg\n" if $debug;
	}
	if ( /^icondir\s*=/ ) {
	    $icondir = $_;
	    $icondir =~ s/^[^=]+=\s*//;
	    $icondir .= "/" if $icondir !~ m#/$# ;
	    print "icondir = $icondir\n" if $debug;
	}
	if ( /^testurl\s*=/ ) {
	    $testurl = $_;
	    $testurl =~ s/^[^=]+=\s*//;
	    print "testurl = $testurl\n" if $debug;
	}
	if ( /^echoping\s*=/ ) {
	    $echoping = $_;
	    $echoping =~ s/^[^=]+=\s*//;
	    print "echoping = $echoping\n" if $debug;
	}
	if ( /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*/ ) {
	    $key = $1;
	    $ip = $2;
	    $p = $3;
	    $pw = $4;
	    print "Key=$key Addr=$ip Port=$p Password=$pw\n" if $debug;
	    $cache{$key}=$ip;
	    $port{$key}=$p;
	    $passwd{$key}=$pw;
	}
    }
    if (! $mrtgdir ) {
	warn("Key htmldir not found in config file $cfgfile!\nExiting!\n");
	exit(2);
    }
    if (! $testurl ) {
	warn("Key testurl not found in config file $cfgfile!\nExiting!\n");
	exit(2);
    }
    if (! $echoping ) {
	warn("Key echoping not found in config file $cfgfile!\nExiting!\n");
	exit(2);
    }
    if (! -x  $echoping) {
	warn("$echoping is not executable: $!\nExiting!\n");
	exit(3);
    }
    if (! $mrtg ) {
	warn("Key mrtg not found in confg file $cfgfile!\nExiting!\n");
	exit(2);
    }
    if (! -x  $mrtg) {
	warn("$mrtg is not executable: $!\nExiting!\n");
	exit(3);
    }
    close(RC);
}

sub GetOptions {
    no strict 'vars';
    my($result);
  
    $result = &getopts('hvf:cd:');
    &Usage if  $opt_h || $result == 0;
    &Version if $opt_v;
    if ($opt_f) {
	if ( -f $opt_f ) {
	    $cfgfile = $opt_f;
	}
	else {
	    warn("Can't open configuration file $opt_f: $!\nExiting.\n");
	    exit(1);
	}
    }
    if ($opt_c) {
	$forcecreate="Yes";
    }
    $debug = $opt_d if $opt_d;
} 

sub Usage { 
    die <<"EndUsage"; 
Gathering Squid proxy cache information for further processing with MRTG.

Usage: gps4a.pl [-h] [-v] [-c] [-d N] [-f cfg_file]

Options:
  -h            Display this message and quit.
  -v            Display version and quit.
  -c            Create the appropriate mrtg directories and mrtg.conf\'s 
                and quit.
  -d N          Print debug messages (Level 2 or anything else = 1 supported) 
  -f cfg_file   Use cfgfile as configuration file instead of .grc 

EndUsage
}

sub Version {
    die <<"EndVersion";
This is $Version.\n\n(C) by Jens Elkner (elkner\@ivs.cs.uni-magdeburg.de).

EndVersion
}
		
sub GetData {
    if ($datadir) {
	die "$datadir does not exist: $!" if (! -d $datadir );
    }
    die "$mrtgdir does not exist: $!" if (! -d $mrtgdir );    
    
    
    foreach $key (sort keys %cache) {
	if (! -f "$mrtgdir/$key/mrtg.conf" || $forcecreate ) {
	    if (! MakeMrtgConf($key) ) {
		warn ("$mrtgdir/$key/mrtg.conf does not exist: $!\nSkipping $cache{$key}!\n");
		next;
	    }
	    else {
		warn("$mrtgdir/$key/mrtg.conf created successfully.\n");
	    }
	}
	next if $forcecreate;
	foreach $obj (@object) {
	    if ($obj eq "echoping") {
		$result{"$obj"} = &DoEchoPing($key);
		next;
	    }
	    $result{"$obj"} = &GetURL($key,$obj);
	}
	&HandleResults($key);
    }
}

sub DoEchoPing {
    my($key) = $_[0];
    my($tmp) = "$echoping -n 3 -t 10 -h $testurl $cache{$key}:$port{$key} |";
    if ( open(PIPE,$tmp) ) {
	$tmp = "";
	while (<PIPE>) {
	    $tmp .= $_;
	}
	close(PIPE);
    }
    else {
	warn "EchoPing failed: $!";
	$tmp = "";
    }
    return $tmp;
}

sub DoMrtg {
    my($key);
    my($my_cwd);
    
    $my_cwd = cwd;
    foreach $key (sort keys %cache) {
	chdir "$mrtgdir/$key";
	print "$mrtgdir/$key\n" if $debug;
	if ( ! -f $lockfile )  {
	    if (! open(LCK,">$lockfile") ) {
		print stderr "Can't open lock file $lockfile for writing: !$\n" .
		    "Check for existing lock files and run mrtg manually\n" .
		    "$mrtg mrtg.conf\n";
		next;
	    }
	    else {
		print LCK "$$\n";
		close(LCK);
		system("$mrtg mrtg.conf");
		unlink($lockfile);
		chdir $my_cwd;
		next;
	    }
	}
	else {
	    print stderr "lock file $mrtgdir/$key/$lockfile exists.\n" .
		"Assuming, mrtg ist still running.\n" .
		"Mrtg was not started for $cache{$key}\n" .
		"If mrtg is not running (check the pid in the lock file),\n" .
	        "remove the lock file and everything should be ok.\n\n";
	}
    }
}

sub HandleResults {
    my($key) = $_[0];
    my($obj,$page,$starttime,$time,$uptime);
    my($tcp,$udp,$select,$swap,$lru,$unlink,$rss,$pfault,$fd,$fdmax,$memory);
    my($requests,$howmany,$dnsserver,$i);
    my($http_count,$http_kb,$http_hit,$ftp_count,$ftp_kb,$ftp_hit,$gopher_count,$gopher_kb,$gopher_hit,$total_count,$total_kb,$total_hit,%table,@proto);
    my($responsetime);
    foreach $obj (@object) {
	$page = $result{$obj};
	if (! $page) {
	    warn "Couldn't get any data for $obj ($cache{$key} )!\n";
	    next;
	}
	print $page if $debug == 2;
	if ($obj eq "info") {
	    $starttime = $page =~ m#Start Time:\s+(\S+.*)\}.*# ? $1 : 0 ;
	    $time =  $page =~ m#Current Time:\s+(\S+.*)\}.*# ? $1 : 0 ;
	    # Connection information
	    $tcp = $page =~ m#TCP connections:\s+(\d+)# ? $1 : 0 ;
	    $udp = $page =~ m#UDP connections:\s+(\d+)# ? $1 : 0 ;
	    $select = $page =~ m#Select loop.*\s+(\d+\.\d+)\sms# ? $1 : 0 ;
	    # Cache information
	    $swap = $page =~ m#Swap.*:\s+(\d+)# ? $1 : 0 ;
	    $lru = $page =~ m#LRU.*\s+(\d+\.\d+)# ? $1 : 0 ;
	    $unlink = $page =~ m#unlinkd:\s+(\d+)# ? $1 : 0 ;
	    # Ressource information
	    $rss = $page =~ m#Resident.*:\s+(\d+)# ? $1 : 0 ;
	    $pfault = $page =~ m#Page faults.*:\s+(\d+)# ? $1 : 0 ;
	    # File descriptor usage
	    $fdmax = $page =~ m#Max.*\sfile\sdesc.*:\s+(\d+)# ? $1 : 0 ;
	    $fd = $page =~ m#Available.* descriptors:\s+(\d+)# ? $fdmax - $1 : 0 ;
	    # Accounted Memory Usage
	    $memory = $page =~ m#Total Accounted\s+=\s+(\d+)# ? $1 : 0 ;
	    $starttime = &str2time($starttime);
	    $time = &str2time($time);
	    $uptime = &delta2str($time - $starttime);
	    &Data2File($key,"tcp_conn","$time $tcp\n");
	    &Data2File($key,"udp_conn","$time $udp\n");
	    &Data2MRTG($key,"tcpudp","$tcp\n$udp\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"select","$time $select\n");
	    $select = int($select + 0.5);
	    &Data2MRTG($key,"select","$select\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"swap","$time $swap\n");
	    &Data2MRTG($key,"swap","$swap\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"lru","$time $lru\n");
	    $lru = int($lru + 0.5);
	    &Data2MRTG($key,"lru","$lru\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"unlink","$time $unlink\n");
	    &Data2MRTG($key,"unlink","$unlink\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"rss","$time $rss\n");
	    &Data2MRTG($key,"rss","$rss\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"pfault","$time $pfault\n");
	    &Data2MRTG($key,"pfault","$pfault\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"fd","$time $fd\n");
	    &Data2MRTG($key,"fd","$fd\n0\n$uptime\n$cache{$key}\n");
	    &Data2File($key,"memory","$time $memory\n");
	    &Data2MRTG($key,"memory","$memory\n0\n$uptime\n$cache{$key}\n");
	}
	if ($obj eq "squid.conf") {
	}
	if ($obj eq "server_list") {
	}
	if ($obj eq "client_list") {
	}
	if ($obj eq "log") {
	}
	if ($obj eq "parameter") {
	}
	if ($obj eq "stats/ipcache") {
	}
	if ($obj eq "stats/fqdncache") {
	}
	if ($obj eq "stats/dns") {
	    $requests = $page =~ m#requests:\s+(\d+)# ? $1 : 0;
	    $howmany = $page =~ m#number of dnsservers:\s+(\d+)# ? $1 : 0;
	    &Data2File($key,"dnsrequests","$time $requests\n");
	    &Data2MRTG($key,"dnsrequests","$requests\n0\n$uptime\n$cache{$key}\n");
	    for ($i=1; $i <= $howmany; $i++) {
		$dnsserver = $page =~ m#\#$i:\s+(\d+)# ? $1 : 0;
		&Data2File($key,"dns$i","$time $dnsserver\n");
		&Data2MRTG($key,"dns$i","$dnsserver\n0\n$uptime\n$cache{$key}\n");
	    }
	}
	if ($obj eq "stats/redirector") {
	}
	if ($obj eq "stats/objects") {
	}
	if ($obj eq "stats/vm_objects") {
	}
	if ($obj eq "stats/utilization") {
	    @proto = ("tcp","udp");
	    $i = index($page,"ICP");
	    $table{"tcp"} = substr($page,0,$i);
	    $table{"udp"} = substr($page,$i);
	    foreach (@proto) {
		if ( $table{$_} =~ m#HTTP.*\s+(\d+\.\d+)\s+\d+\s+(\d+)\s+(\d+)\s*\}# ) {
		    $http_hit = $1;
		    $http_count = $2;
		    $http_kb = $3;
		}
		if ( $table{$_} =~ m#FTP.*\s+(\d+\.\d+)\s+\d+\s+(\d+)\s+(\d+)\s*\}# ) {
		    $ftp_hit = $1;
		    $ftp_count = $2;
		    $ftp_kb = $3;
		}
		if ( $table{$_} =~ m#GOPHER.*\s+(\d+\.\d+)\s+\d+\s+(\d+)\s+(\d+)\s*\}# ) {
		    $gopher_hit = $1;
		    $gopher_count = $2;
		    $gopher_kb = $3;
		}
		if ( $table{$_} =~ m#TOTAL.*\s+(\d+\.\d+)\s+\d+\s+(\d+)\s+(\d+)\s*\}# ) {
		    $total_hit = $1;
		    $total_count = $2;
		    $total_kb = $3;
		}
		&Data2File($key,"${_}_totalN","$time $total_count\n");
		&Data2File($key,"${_}_httpN","$time $http_count\n");
		&Data2File($key,"${_}_ftpN","$time $ftp_count\n");
		&Data2File($key,"${_}_gopherN","$time $gopher_count\n");
		# We put totals and http together
		&Data2MRTG($key,"${_}_totalN","$total_count\n$http_count\n$uptime\n$cache{$key}\n");
		# We put ftp and gopher together
		&Data2MRTG($key,"${_}_ftpN","$ftp_count\n$gopher_count\n$uptime\n$cache{$key}\n");
		&Data2File($key,"${_}_totalKB","$time $total_kb\n");
		&Data2File($key,"${_}_httpKB","$time $http_kb\n");
		&Data2File($key,"${_}_ftpKB","$time $ftp_kb\n");
		&Data2File($key,"${_}_gopherKB","$time $gopher_kb\n");
		# We put totals and http together
		&Data2MRTG($key,"${_}_totalKB","$total_kb\n$http_kb\n$uptime\n$cache{$key}\n");
		# We put ftp and gopher together
		&Data2MRTG($key,"${_}_ftpKB","$ftp_kb\n$gopher_kb\n$uptime\n$cache{$key}\n");
		&Data2File($key,"${_}_totalH","$time $total_hit\n");
		&Data2File($key,"${_}_httpH","$time $http_hit\n");
		&Data2File($key,"${_}_ftpH","$time $ftp_hit\n");
		&Data2File($key,"${_}_gopherH","$time $gopher_hit\n");
		# We put totals and http together
		&Data2MRTG($key,"${_}_totalH","$total_hit\n$http_hit\n$uptime\n$cache{$key}\n");
		# We put ftp and gopher together
		&Data2MRTG($key,"${_}_ftpH","$ftp_hit\n$gopher_hit\n$uptime\n$cache{$key}\n");
		print "$_:\nHTTP: $http_count $http_kb KB\nFTP:  $ftp_count $ftp_kb\nTOTAL: $total_count $total_kb\n" if $debug;
	    }
	}
	if ($obj eq "stats/io") {
	}
	if ($obj eq "stats/reply_headers") {
	}
	if ($obj eq "stats/filedescriptors") {
	}
	if ($obj eq "stats/netdb") {
	}
	if ($obj eq "shutdown") {
	}
	if ($obj eq "refresh") {
	}
	if ($obj eq "remove") {
	}
	if ($obj eq "echoping") {
	    $responsetime = $page =~ m#Median time:\s+(\d+\.\d+)# ? $1 : 0;
	    $responsetime = int($responsetime *1000 + 0.5);
	    &Data2File($key,"${_}eping","$time $responsetime\n");
	    &Data2MRTG($key,"${_}eping","$responsetime\n0\n$uptime\n$cache{$key}\n");
	}
    }
}

# Append data in gnuplot format to the specified file
# I need this for generating non-pix graphs for my diploma sometimes later :)
sub Data2File {
    return if (! $datadir);
    if (! open(FILE,">>$datadir/$_[0]/$_[1]") ) {
	warn "Could not open $datadir/$_[0]/$_[1] for writing: $!";
	return;
    }
    print FILE $_[2];
    close(FILE);
}

# Writing data to the specified file, which is cat direct to MRTG for generating
# nice pix graphs for the web
# Overwrites the Old content of the file !!!
sub Data2MRTG {
    if (! open(FILE,">$mrtgdir/$_[0]/data/$_[1]") ) {
	warn "Could not open $mrtgdir/$_[0]/data/$_[1] for writing: $!";
	return;
    }
    print FILE $_[2];
    close(FILE);
}

sub delta2str {
    my ($time) = @_;
    my ($days, $hours, $minutes, $seconds,$d,$h);
    $days = int ($time / 86400);
    $time = $time - ($days * 86400);
    $hours = int ($time / 3600);
    $time = $time - ($hours * 3600);
    $minutes = int ($time / 60);
    $time = $time - ($minutes * 60);
    $seconds = $time;
    $d = ($days > 1) ? "s" : "";
    $h = ($hours > 1) ? "s" : "";
    $time = sprintf("%d day%s and %02d:%02d:%02d hour%s",$days,$d,
		    $hours,$minutes,$seconds,$h);
    return $time;
}

sub GetURL {
    my($key) = $_[0];
    my($object) = $_[1];
    my($received) = "";
    my($sockaddr) = 'S n a4 x8';
    my($name, $aliases, $proto) = getprotobyname("tcp");
    my($fqdn, $aliases, $type, $len, $thataddr) = gethostbyname($cache{$key});
    my($thissock) = pack($sockaddr, &AF_INET, 0, "\0\0\0\0");
    my($that) = pack($sockaddr, &AF_INET, $port{$key}, $thataddr);
    die "socket: $!\n" unless socket (SOCK, &AF_INET, &SOCK_STREAM, $proto);
    die "bind: $!\n" unless bind (SOCK, $thissock);
    die "$cache{$key}:$port{$key} : $!\n" unless connect (SOCK, $that);
    select (SOCK); $| = 1;
    select (STDOUT);
    my($url) = "cache_object://" . $cache{$key} . "/" . $object;
    $url .= "\@" . $passwd{$key} if $passwd{$key};
    print "URL: $url\n" if $debug;
    print SOCK "GET $url HTTP/1.1\r\nAccept: */*\r\n\r\n";
    while (<SOCK>) {
	s/$//g;
	$received .= $_;
    }
    close(SOCK);
    return $received;
}

sub MakeMrtgConf {
    my($keyword) = $_[0];
    my($the_cwd);
  
    if (! -d "$mrtgdir/$keyword" ) {
	if (! mkdir("$mrtgdir/$keyword","0755") ) {
	    warn("Could not create the directory $mrtgdir/$keyword : $!\n");
	    return(0);
	}
	chmod 0755, "$mrtgdir/$keyword";
    }
    if (! -d "$mrtgdir/$keyword/data") {
	if (! mkdir("$mrtgdir/$keyword/data","0755") ) {
	    warn("Could not create the directory $mrtgdir/$keyword/data: $!\n");
	    return(0);
	}
	chmod 0755, "$mrtgdir/$keyword/data";
    }
    if ( -f "$mrtgdir/$keyword/mrtg.conf" && -d "$mrtgdir/$keyword/data") {
	return (1);
    }
    if (! open(CF,">$mrtgdir/$keyword/mrtg.conf")) {
	warn("Could not create $mrtgdir/$keyword/mrtg.conf: $!\n");
	return(0);
    }
    print CF << "EndConfig";
######################################################################
# Multi Router Traffic Grapher
######################################################################

# ####################
# Global Configuration 
# ####################

# Where should the logfiles, and webpages be created?

WorkDir: .

# --------------------------
# Optional Global Parameters
# --------------------------

# browser (Netscape) reload in seconds
# Refresh: 600

# Intervall in minutes when mrtg execs
# Interval: 5

# expire files for gif's etc.
WriteExpires: No

# MRTG Icons
IconDir: $icondir


# #################################################
# ProxyCache.CS.Uni-Magdeburg.De    (cache)
# #################################################

# DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS DNS

Target[dns1]: `cat data/dns1` * 60
MaxBytes[dns1]: 1000
WithPeak[dns1]: ymw
Options[dns1]: growright, nopercent
YLegend[dns1]: requests/min
ShortLegend[dns1]: &nbsp;req/min &nbsp;
Legend1[dns1]: DNS request/min given to the external DNS server
Legend2[dns1]: &nbsp;
Legend3[dns1]: 5 min. max. DNS requests/min given to the external DNS server
Legend4[dns1]: &nbsp; 
LegendI[dns1]: :&nbsp;
LegendO[dns1]:
Colours[dns1]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[dns1]: DNS #1 $cache{$keyword}
PageTop[dns1]: <H1>DNS #1 $cache{$keyword}</H1>
 Number of DNS requests given to DNS server #1, which could not
 be resolved through the proxy cache's own IP-Cache.

Target[dns2]: `cat data/dns2` * 60
MaxBytes[dns2]: 1000
WithPeak[dns2]: ymw
Options[dns2]: growright, nopercent
YLegend[dns2]: requests/min
ShortLegend[dns2]: &nbsp;req/min &nbsp;
Legend1[dns2]: DNS request/min given to the external DNS server
Legend2[dns2]: &nbsp;
Legend3[dns2]: 5 min. max. DNS requests/min given to the external DNS server
Legend4[dns2]: &nbsp; 
LegendI[dns2]: :&nbsp;
LegendO[dns2]:
Colours[dns2]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[dns2]: DNS #2 $cache{$keyword}
PageTop[dns2]: <H1>DNS #2 $cache{$keyword}</H1>
 Number of DNS req. given to DNS server #2, which could not
 be resolved through the proxy cache's own IP-Cache.

Target[dns3]: `cat data/dns3` * 60
MaxBytes[dns3]: 1000
WithPeak[dns3]: ymw
Options[dns3]: growright, nopercent
YLegend[dns3]: requests/min
ShortLegend[dns3]: &nbsp;
Legend1[dns3]: DNS request/min given to the external DNS server
Legend2[dns3]: &nbsp;req/min &nbsp;
Legend3[dns3]: 5 min. max. DNS requests/min given to the external DNS server
Legend4[dns3]: &nbsp; 
LegendI[dns3]: :&nbsp;
LegendO[dns3]:
Colours[dns3]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[dns3]: DNS #3 $cache{$keyword}
PageTop[dns3]: <H1>DNS #3 $cache{$keyword}</H1>
 Number of DNS requests given to DNS server #3, which could not
 be resolved through the proxy cache's own IP-Cache.

Target[dns4]: `cat data/dns4` * 60
MaxBytes[dns4]: 1000
WithPeak[dns4]: ymw
Options[dns4]: growright, nopercent
YLegend[dns4]: DNS requests
ShortLegend[dns4]: &nbsp;
Legend1[dns4]: DNS request/min given to the external DNS server
Legend2[dns4]: &nbsp;req/min &nbsp;
Legend3[dns4]: 5 min. max. DNS requests/min given to the external DNS server
Legend4[dns4]: &nbsp; 
LegendI[dns4]: :&nbsp;
LegendO[dns4]:
Colours[dns4]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[dns4]: DNS #4 $cache{$keyword}
PageTop[dns4]: <H1>DNS #4 $cache{$keyword}</H1>
 Number of DNS requests given to DNS server #4, which could not
 be resolved through the proxy cache's own IP-Cache.

Target[dns5]: `cat data/dns5` * 60
MaxBytes[dns5]: 1000
WithPeak[dns5]: ymw
Options[dns5]: growright, nopercent
YLegend[dns5]: DNS requests
ShortLegend[dns5]: &nbsp;req/min &nbsp;
Legend1[dns5]: DNS request/min given to the external DNS server
Legend2[dns5]: &nbsp;
Legend3[dns5]: 5 min. max. DNS requests/min given to the external DNS server
Legend4[dns5]: &nbsp; 
LegendI[dns5]: :&nbsp;
LegendO[dns5]:
Colours[dns5]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[dns5]: DNS #5 $cache{$keyword}
PageTop[dns5]: <H1>DNS #5 $cache{$keyword}</H1>
 Number of DNS requests given to DNS server #5 by $cache{$keyword}, which could not
 be resolved through the proxy cache's own IP-Cache.

Target[eping]: `cat data/eping`
MaxBytes[eping]: 3000
WithPeak[eping]: ymw
Options[eping]: growright, gauge, nopercent
YLegend[eping]: ms
ShortLegend[eping]: ms
Legend1[eping]: Cache response time in Milliseconds
Legend2[eping]: &nbsp;
Legend3[eping]: 5 min max. cache response time in Milliseconds 
Legend4[eping]: &nbsp;
LegendI[eping]: :&nbsp;
LegendO[eping]:
Colours[eping]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[eping]: Echoping $cache{$keyword}
PageTop[eping]: <H1>Echoping $cache{$keyword}</H1>
 Median response time of the proxy cache in milliseconds.

Target[fd]: `cat data/fd`
MaxBytes[fd]: 4096
WithPeak[fd]: ymw
Options[fd]: growright, gauge, nopercent
YLegend[fd]: fd
ShortLegend[fd]: fd
Legend1[fd]: file descriptor usage
Legend2[fd]: &nbsp;
Legend3[fd]: 5 min max. file descriptor usage 
Legend4[fd]: &nbsp;
LegendI[fd]: :&nbsp;
LegendO[fd]:
Colours[fd]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[fd]: FD usage $cache{$keyword}
PageTop[fd]: <H1>FD usage $cache{$keyword}</H1>
 Number of file descriptors currently used by the proxy cache.

Target[lru]: `cat data/lru`
MaxBytes[lru]: 365
WithPeak[lru]: ymw
Options[lru]: growright, gauge, nopercent
YLegend[lru]: days
ShortLegend[lru]: days
Legend1[lru]: storage LRU expiration age in days
Legend2[lru]: &nbsp;
Legend3[lru]: 5 min max. storage LRU expiration age in days
Legend4[lru]: &nbsp;
LegendI[lru]: :&nbsp;
LegendO[lru]:
Colours[lru]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[lru]: LRU age $cache{$keyword}
PageTop[lru]: <H1>LRU age $cache{$keyword}</H1>
 Time until the next storage LRU expiration will be started.

# set MaxBytes to Bytes of RAM you have and AbsMax twice this value
# right now it is set to 384 MB
Target[memory]: `cat data/memory` * 1024
MaxBytes[memory]: 402653184
AbsMax[memory]: 805306368
WithPeak[memory]: ymw
Options[memory]: growright, gauge
YLegend[memory]: MB
ShortLegend[memory]: MB
Legend1[memory]: Total accounted memory usage in MB
Legend2[memory]: &nbsp;
Legend3[memory]: 5 min max. total accounted memory usage in MB
Legend4[memory]: &nbsp;
LegendI[memory]: :&nbsp;
LegendO[memory]:
Colours[memory]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[memory]: Memory $cache{$keyword}
PageTop[memory]: <H1>Memory $cache{$keyword}</H1>
 Total accounted memory usage by the proxy cache in MBytes.

Target[pfault]: `cat data/pfault` * 60
MaxBytes[pfault]: 1000000
WithPeak[pfault]: ymw
Options[pfault]: growright, nopercent
YLegend[pfault]: page faults
ShortLegend[pfault]: page faults
Legend1[pfault]: page faults / min 
Legend2[pfault]: &nbsp;
Legend3[pfault]: 5 min max. page faults / min
Legend4[pfault]: &nbsp;
LegendI[pfault]: :&nbsp;
LegendO[pfault]:
Colours[pfault]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[pfault]: Page Faults $cache{$keyword}
PageTop[pfault]: <H1>Page Faults $cache{$keyword}</H1>
 Page Faults per minute. Depending on the operating system, it does
 <B>NOT</B> imply, that the system is swapping (e.g. Solaris), but it might be
 (e.g. HP-UX).

# set MaxBytes to Bytes of RAM you have
# right now it is set to 384 MB
Target[rss]: `cat data/rss` * 1024
MaxBytes[rss]: 402653184
WithPeak[rss]: ymw
Options[rss]: growright, gauge
YLegend[rss]: MB
ShortLegend[rss]: MB
Legend1[rss]: Maximum resident size cache in MB 
Legend2[rss]: &nbsp;
Legend3[rss]: 5 min max. maximum resident size in MB
Legend4[rss]: &nbsp;
LegendI[rss]: :&nbsp;
LegendO[rss]:
Colours[rss]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[rss]: RSS $cache{$keyword}
PageTop[rss]: <H1>Maximum RSS $cache{$keyword}</H1>
 The maximum resident size of the proxy cache in MB.

# set this value equivalent to the cache_swap line in your squid.conf
# because there is an overflow bug, we can\'t normalize it to Bytes :(( 
Target[swap]: `cat data/swap`
MaxBytes[swap]: 12228
WithPeak[swap]: ymw
Options[swap]: growright, gauge
YLegend[swap]: MB
ShortLegend[swap]: MB
Legend1[swap]: Storage swap size in MB 
Legend2[swap]: &nbsp;
Legend3[swap]: 5 min max. Storage swap size in MB
Legend4[swap]: &nbsp;
LegendI[swap]: :&nbsp;
LegendO[swap]:
Colours[swap]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[swap]: Storage Swap $cache{$keyword}
PageTop[swap]: <H1>Storage Swap $cache{$keyword}</H1>
 The storage (disk) swap size of the proxy cache in MB.

Target[select]: `cat data/select`
MaxBytes[select]: 1000
WithPeak[select]: ymw
Options[select]: growright, gauge, nopercent
YLegend[select]: ms
ShortLegend[select]: ms
Legend1[select]: average time between 2 consecutive select loop calls in Milliseconds 
Legend2[select]: &nbsp;
Legend3[select]: 5 min max. time between 2 consecutive select loop calls in Milliseconds 
Legend4[select]: &nbsp;
LegendI[select]: :&nbsp;
LegendO[select]:
Colours[select]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[select]: Select Loop $cache{$keyword}
PageTop[select]: <H1>Select Loop $cache{$keyword}</H1>
 The average time between 2 consecutive select loop calls in Milliseconds.
 It might be an indicator, how busy the proxy cache is (the shorter the time,
 the more requests have been made) and what time is needed for 1 select loop.

Target[unlink]: `cat data/unlink` * 60
MaxBytes[unlink]: 1000000
WithPeak[unlink]: ymw
Options[unlink]: growright, nopercent
YLegend[unlink]: unlinks/min
ShortLegend[unlink]: unlinks/min
Legend1[unlink]: Requests per minute given to unlinkd 
Legend2[unlink]: &nbsp;
Legend3[unlink]: 5 min max. per minute given to unlinkd
Legend4[unlink]: &nbsp;
LegendI[unlink]: :&nbsp;
LegendO[unlink]:
Colours[unlink]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[unlink]: Unlinks $cache{$keyword}
PageTop[unlink]: <H1>Unlinks $cache{$keyword}</H1>
 Requests per minute given to unlinkd (daemon responsible for deleting stored
 cache objects).

Target[tcpudp]: `cat data/tcpudp` * 60
MaxBytes[tcpudp]: 1000000
WithPeak[tcpudp]: ymw
Options[tcpudp]: growright, nopercent
YLegend[tcpudp]: conn/min
ShortLegend[tcpudp]: conn/min
Legend1[tcpudp]: TCP conn/min 
Legend2[tcpudp]: UDP conn/min
Legend3[tcpudp]: 5 min max.TCP conn/min 
Legend4[tcpudp]: 5 min max.UDP conn/min
LegendI[tcpudp]: &nbsp;TCP :&nbsp;
LegendO[tcpudp]: &nbsp;UDP :&nbsp;
Colours[tcpudp]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[tcpudp]: Connections $cache{$keyword}
PageTop[tcpudp]: <H1>Connections $cache{$keyword}</H1>
 Average Number of TCP and UDP connections per minute.

Target[tcp_totalN]: `cat data/tcp_totalN` * 60
MaxBytes[tcp_totalN]: 1000000
WithPeak[tcp_totalN]: ymw
Options[tcp_totalN]: growright, nopercent
YLegend[tcp_totalN]: req/min
ShortLegend[tcp_totalN]: req/min
Legend1[tcp_totalN]: HTTP TCP requests/min 
Legend2[tcp_totalN]: Total TCP requests/min
Legend3[tcp_totalN]: 5 min max. Total TCP requests/min 
Legend4[tcp_totalN]: 5 min max. HTTP TCP requests/min
LegendI[tcp_totalN]: &nbsp;Total TCP :&nbsp;
LegendO[tcp_totalN]: &nbsp;HTTP TCP :&nbsp;
Colours[tcp_totalN]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[tcp_totalN]:  TCP: Total, HTTP requests $cache{$keyword}
PageTop[tcp_totalN]: <H1>TCP: Total, HTTP requests $cache{$keyword}</H1>
 Average Number of TCP requests per minute (Totals and HTTP).

Target[tcp_totalKB]: `cat data/tcp_totalKB`
MaxBytes[tcp_totalKB]: 1937500
WithPeak[tcp_totalKB]: ymw
Options[tcp_totalKB]: growright
#YLegend[tcp_totalKB]: 
#ShortLegend[tcp_totalKB]:
Legend1[tcp_totalKB]: HTTP TCP KB/s
Legend2[tcp_totalKB]: Total TCP KB/s
Legend3[tcp_totalKB]: 5 min max. Total TCP KB/s 
Legend4[tcp_totalKB]: 5 min max. HTTP TCP KB/s
LegendI[tcp_totalKB]: &nbsp;Total TCP :&nbsp;
LegendO[tcp_totalKB]: &nbsp;HTTP TCP :&nbsp;
Colours[tcp_totalKB]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[tcp_totalKB]:  TCP: Total, HTTP KB $cache{$keyword}
PageTop[tcp_totalKB]: <H1>TCP: Total, HTTP KB $cache{$keyword}</H1>
 Average transfer rate via TCP in KB/s (Total and HTTP).

Target[tcp_ftpN]: `cat data/tcp_ftpN` * 60
MaxBytes[tcp_ftpN]: 1000000
WithPeak[tcp_ftpN]: ymw
Options[tcp_ftpN]: growright, nopercent
YLegend[tcp_ftpN]: req/min
ShortLegend[tcp_ftpN]: req/min
Legend1[tcp_ftpN]: FTP TCP requests/min 
Legend2[tcp_ftpN]: Gopher TCP requests/min
Legend3[tcp_ftpN]: 5 min max. FTP TCP requests/min 
Legend4[tcp_ftpN]: 5 min max. Gopher TCP requests/min
LegendI[tcp_ftpN]: &nbsp;FTP TCP :&nbsp;
LegendO[tcp_ftpN]: &nbsp;Gopher TCP :&nbsp;
Colours[tcp_ftpN]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[tcp_ftpN]:  TCP: FTP, Gopher requests $cache{$keyword}
PageTop[tcp_ftpN]: <H1>TCP: FTP, Gopher requests $cache{$keyword}</H1>
 Average Number of TCP requests per minute (FTP and Gopher).

Target[tcp_ftpKB]: `cat data/tcp_ftpKB`
MaxBytes[tcp_ftpKB]: 1937500
WithPeak[tcp_ftpKB]: ymw
Options[tcp_ftpKB]: growright
#YLegend[tcp_ftpKB]: 
#ShortLegend[tcp_ftpKB]: 
Legend1[tcp_ftpKB]: FTP TCP KB/s
Legend2[tcp_ftpKB]: Gopher TCP KB/s
Legend3[tcp_ftpKB]: 5 min max. FTP TCP KB/s 
Legend4[tcp_ftpKB]: 5 min max. Gopher TCP KB/s
LegendI[tcp_ftpKB]: &nbsp;FTP TCP :&nbsp;
LegendO[tcp_ftpKB]: &nbsp;Gopher TCP :&nbsp;
Colours[tcp_ftpKB]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[tcp_ftpKB]:  TCP: FTP, Gopher KB $cache{$keyword}
PageTop[tcp_ftpKB]: <H1>TCP: FTP, Gopher KB $cache{$keyword}</H1>
 Average transfer rate via TCP in KB/s (FTP and Gopher).

Target[udp_totalN]: `cat data/udp_totalN` * 60
MaxBytes[udp_totalN]: 1000000
WithPeak[udp_totalN]: ymw
Options[udp_totalN]: growright, nopercent
YLegend[udp_totalN]: req/min
ShortLegend[udp_totalN]: req/min
Legend1[udp_totalN]: HTTP UDP requests/min 
Legend2[udp_totalN]: Total UDP requests/min
Legend3[udp_totalN]: 5 min max. Total UDP requests/min 
Legend4[udp_totalN]: 5 min max. HTTP UDP requests/min
LegendI[udp_totalN]: &nbsp;Total UDP :&nbsp;
LegendO[udp_totalN]: &nbsp;HTTP UDP :&nbsp;
Colours[udp_totalN]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[udp_totalN]:  UDP: Total, HTTP requests $cache{$keyword}
PageTop[udp_totalN]: <H1>UDP: Total, HTTP requests $cache{$keyword}</H1>
 Average Number of UDP requests per minute (Totals and HTTP).

Target[udp_totalKB]: `cat data/udp_totalKB`
MaxBytes[udp_totalKB]: 1937500
WithPeak[udp_totalKB]: ymw
Options[udp_totalKB]: growright
#YLegend[udp_totalKB]: 
#ShortLegend[udp_totalKB]:
Legend1[udp_totalKB]: HTTP UDP KB/s
Legend2[udp_totalKB]: Total UDP KB/s
Legend3[udp_totalKB]: 5 min max. Total UDP KB/s 
Legend4[udp_totalKB]: 5 min max. HTTP UDP KB/s
LegendI[udp_totalKB]: &nbsp;Total UDP :&nbsp;
LegendO[udp_totalKB]: &nbsp;HTTP UDP :&nbsp;
Colours[udp_totalKB]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[udp_totalKB]:  UDP: Total, HTTP KB $cache{$keyword}
PageTop[udp_totalKB]: <H1>UDP: Total, HTTP KB $cache{$keyword}</H1>
 Average transfer rate via UDP in KB/s (Total and HTTP).

Target[udp_ftpN]: `cat data/udp_ftpN` * 60
MaxBytes[udp_ftpN]: 1000000
WithPeak[udp_ftpN]: ymw
Options[udp_ftpN]: growright, nopercent
YLegend[udp_ftpN]: req/min
ShortLegend[udp_ftpN]: req/min
Legend1[udp_ftpN]: FTP UDP requests/min 
Legend2[udp_ftpN]: Gopher UDP requests/min
Legend3[udp_ftpN]: 5 min max. FTP UDP requests/min 
Legend4[udp_ftpN]: 5 min max. Gopher UDP requests/min
LegendI[udp_ftpN]: &nbsp;FTP UDP :&nbsp;
LegendO[udp_ftpN]: &nbsp;Gopher UDP :&nbsp;
Colours[udp_ftpN]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[udp_ftpN]:  UDP: FTP, Gopher requests $cache{$keyword}
PageTop[udp_ftpN]: <H1>UDP: FTP, Gopher requests $cache{$keyword}</H1>
 Average Number of UDP requests per minute (FTP and Gopher).

Target[udp_ftpKB]: `cat data/udp_ftpKB`
MaxBytes[udp_ftpKB]: 1937500
WithPeak[udp_ftpKB]: ymw
Options[udp_ftpKB]: growright
#YLegend[udp_ftpKB]: 
#ShortLegend[udp_ftpKB]: 
Legend1[udp_ftpKB]: FTP UDP KB/s
Legend2[udp_ftpKB]: Gopher UDP KB/s
Legend3[udp_ftpKB]: 5 min max. FTP UDP KB/s 
Legend4[udp_ftpKB]: 5 min max. Gopher UDP KB/s
LegendI[udp_ftpKB]: &nbsp;FTP UDP :&nbsp;
LegendO[udp_ftpKB]: &nbsp;Gopher UDP :&nbsp;
Colours[udp_ftpKB]: BLUE#1000ff,DARK GREEN#006600,VIOLET#ff00ff,ORANGE#ff8022
Title[udp_ftpKB]:  UDP: FTP, Gopher KB $cache{$keyword}
PageTop[udp_ftpKB]: <H1>UDP: FTP, Gopher KB $cache{$keyword}</H1>
 Average transfer rate via UDP in KB/s (FTP and Gopher).

EndConfig
	close(CF);
	return(1);
}
