Revision 20 (by dpavlin, 2009/07/19 19:06:10) added ldap and zebra to filter
#!/usr/bin/perl

use warnings;
use strict;

use Data::Dump qw/dump/;
use RRD::Simple;
use POSIX qw/mktime/;
use Getopt::Long;

my $debug = 0;
my $zoom = 2;

my $only_veid;
my $by_veid;
my $too_small = 64;	# M
my $filter = qr{(apache|mysql|postgres|cgi-bin|SIP|ldap|zebra)};

my $use = 'VSZ';

GetOptions(
	'debug!'   => \$debug,
	'zoom=i'   => \$zoom,
	'only-veid=i' => \$only_veid,
	'by-veid!' => \$by_veid,
	'size=i'   => \$too_small,
	'use=s'    => \$use,
);


my $veids;
my $vsz;

$too_small *= 1024; # k

sub count {
	my $file = shift;
	open(my $fh, '<', $file) || die "$file: $!";

	my $t = mktime( 0, $5, $4, $3, $2 - 1, $1 - 1900 ) if $file =~ m{(\d\d\d\d)-(\d\d)-(\d\d)/(\d\d)(\d\d)};

#	warn "# $file ", -s $file, " bytes [$t]\n" if $debug;
	print STDERR "\n$file\t";

	my $cols = <$fh>;
	$cols =~ s/^\s+//;
	my @c = split(/\s+/,$cols);
#	warn "# c = ",dump( @c );
	our $cp;
	$cp->{$c[$_]} = $_ foreach 0 .. $#c;
	our @r;
	sub c {
		return $r[ $cp->{$_[0]} ];	# XXX speedup

		my $name = shift;
		my $n = $cp->{$name};
		die "no column $name in ",dump( $cp ) unless defined $n;
		return $r[$n];
	}

	while(<$fh>) {
		chomp;
		s/^\s+//g;
		s/\s+$//g;
		@r = split(/\s+/, $_, $#c + 1 );

		my $veid = c('VEID');
		next if defined $only_veid && $only_veid != $veid;
		$veid =~ s/^0$/_hw_0/;

		my $s = c($use);
		my $cmd = c('COMMAND');
		if ( ! $by_veid && $cmd =~ $filter ) {

			$veid .= '-' . $1;
			$vsz->{$t}->{$veid} += $s * 1024;
			print STDERR uc(substr($1,0,1));

		} elsif ( $s < $too_small || $by_veid ) {

			$vsz->{$t}->{$veid}+= $s * 1024;
			print STDERR ".";

		} else {

			$cmd =~ s{-.+$}{};
			$cmd =~ s{^/\S+/(\w+?)}{$1};
			$cmd =~ s{^\w+ /\S+/(\w+?)}{$1};
			$cmd =~ s{:?\s+.*$}{};
			$cmd =~ s{\W+}{_}g;
			$veid .= '-' . $cmd;
			$veid = substr($veid,0,16);
			$vsz->{$t}->{$veid}+= $s * 1024;
			print STDERR substr($cmd,0,1);
		}
		$veids->{$veid}++;
	}

}

print STDERR "parsing ps with grouping < $too_small k";

count $_ foreach @ARGV;

#print "VSZ: ",dump( $vsz );

my @veids = sort keys %$veids;
warn "# veids = ",dump( @veids );

my $rrd_file = $use . '.rrd';
unlink $rrd_file if -e $rrd_file;

my @t = sort keys %$vsz;

print "\ndrawing $#t intervals ", $t[0], " - ", $t[$#t];

my $rrd = RRD::Simple->new( file => $rrd_file );
$rrd->create( map { ( $_ => 'GAUGE' ) } @veids );

foreach my $t ( @t ) {
	print STDERR ".";
#	warn "## ",dump( %{ $vsz->{$t} } );

	eval {
		$rrd->update($t, map {
			( $_ => $vsz->{$t}->{$_} )
		} @veids );
	};
	warn "SKIP $t: $@\n" if $@;
}

$rrd->graph(
	sources => [ sort @veids ],
	source_drawtypes => [ map { $_ ? 'STACK' : 'AREA' } 0 .. $#veids ],
	periods => [ qw/hour 6hour 12hour day week month year 3years/ ],
	extended_legend => 1,
	title => "$use > $too_small K",
	width =>  500 * $zoom,
	height => 200 * $zoom,
);