#!/usr/bin/perl

###########################################################################
# Author: Vladimir Vuksan http://vuksan.com/linux/
# Collects NFSd v3 metrics
# Currently it will collect and send to Ganglia following metrics
# 3 -> getattr, 4 -> setattr, 5 -> lookup, 6 -> access, 8-> read
# 9 -> write, 10 -> create, 14 -> remove
# If you would like some of the other stats e.g. mkdir append them 
# below to @which_metrics
###########################################################################
$gmetric_command = "/usr/bin/gmetric";

if ( ! -x $gmetric_command ) {
	die("Gmetric command is not executable. Exiting...");
}

@which_metrics = split(/ /, "3 4 5 6 8 9 10 14");

# Where to store the last stats file
$tmp_dir_base="/var/lib/ganglia/metrics/";
$tmp_stats_file=$tmp_dir_base . "/" . "nfsd_stats";

# Where are the disk stats stored
$proc_file="/proc/net/rpc/nfsd";

###########################################################################
# This is the order of metrics in /proc/net/rpc/nfsd
###########################################################################
%nfsd_stat = (
	3 => "getattr",
	4 => "setattr",
	5 => "lookup",
	6 => "access",
	7 => "readlink",
	8 => "read",
	9 => "write",
	10 => "create",
	11 => "mkdir",
	12 => "symlink",
	13 => "mknod",
	14 => "remove",
	15 => "rmdir",
	16 => "rename",
	17 => "link",
	18 => "readdir",
	19 => "readdirplus",
	20 => "fsstat",
	21 => "fsinfo",
	22 => "pathconf",
	23 => "commit"
);

# If the tmp directory doesn't exit create it
if ( ! -d $tmp_dir_base ) {
	system("mkdir -p $tmp_dir_base");
}

###############################################################################
# We need to store a baseline with statistics. If it's not there let's dump 
# it into the file. Don't do anything else
###############################################################################
if ( ! -f $tmp_stats_file ) {
	print "Creating baseline. No output this cycle\n";
	system("cat $proc_file > $tmp_stats_file");
} else {

	# Let's read in the file from the last poll
	open(OLDNFSDSTATUS, "< $tmp_stats_file");
	
	while(<OLDNFSDSTATUS>)
	{
		my($line) = $_;
		chomp($line);
		if ( /^proc3/ ) {
			@old_stats = split(/ /,$line);
		}
	}
	
	close(OLDNFSDSTATUS);

	open(NFSDSTATUS, "< $proc_file");
	
	while(<NFSDSTATUS>)
	{
		my($line) = $_;
		chomp($line);
		if ( /^proc3/ ) {
			@new_stats = split(/ /,$line);
			system("echo '$line' >  $tmp_stats_file");
		}
	}
	
	close(NFSDSTATUS);

	# Update the nfsd_stats file 
#	system("cat $proc_file > $tmp_stats_file");

	# Calculate deltas and send them to ganglia
	for ( $i = 0 ; $i <= $#which_metrics; $i++ ) {
		$metric = $which_metrics[$i];
		$delta = $new_stats[$metric] - $old_stats[$metric];
		print "$nfsd_stat{$metric} = $delta\n";
		system($gmetric_command . " -tuint16 -ucalls -n nfsd_v3_" . $nfsd_stat{$metric} . " -v " . $delta);
	}

}
