201 lines
6.6 KiB
Perl
Executable file
201 lines
6.6 KiB
Perl
Executable file
#!/usr/bin/perl
|
|
|
|
# statgraph: A simple host resource graphing tool
|
|
# Copyright (C) 2004-2011 Ben Charlton <ben@spod.cx>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; see the file COPYING. If not, write to the Free
|
|
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
# MA 02110-1301 USA, or see http://www.gnu.org
|
|
|
|
use strict;
|
|
use StatGraph;
|
|
|
|
## TODO: configure with getopt
|
|
my $config = "statgraph.conf";
|
|
|
|
## Get configuration
|
|
open CONFIG, $config || die "Cannot open $config: $!";
|
|
my @CONFIG = (<CONFIG>);
|
|
close CONFIG;
|
|
|
|
my %CONFIG = confparse(\@CONFIG);
|
|
my %HOSTS = %{$CONFIG{hosts}};
|
|
%CONFIG = %{$CONFIG{config}};
|
|
|
|
## Set default configuration options if they've not been specified
|
|
my $defaultport = $CONFIG{defaultport} || 27001;
|
|
my $rrdlocation = $CONFIG{rrdlocation} || "rrd/";
|
|
|
|
|
|
my $pid = $$;
|
|
my $parent = 0;
|
|
my @kids = ();
|
|
my $host;
|
|
|
|
## Main loop - run once for each host
|
|
FORK: foreach my $currhost (keys %HOSTS) {
|
|
|
|
my $newpid = fork();
|
|
if ( not defined $newpid ) {
|
|
# if return value of fork() is undef, something went wrong
|
|
die "fork didn't work: $!\n";
|
|
}
|
|
elsif ( $newpid == 0 ) {
|
|
# if return value is 0, this is the child process
|
|
$parent = $pid; # which has a parent called $pid
|
|
$pid = $$; # and which will have a process ID of its very own
|
|
@kids = (); # the child doesn't want this baggage from the parent
|
|
$host = $currhost;
|
|
last FORK; # and we don't want the child making babies either
|
|
}
|
|
else {
|
|
# the parent process is returned the PID of the newborn by fork()
|
|
push @kids, $newpid;
|
|
}
|
|
|
|
}
|
|
|
|
if ( $parent ) {
|
|
# if I have a parent, i.e. if I'm the child process
|
|
my %results;
|
|
my %ignore;
|
|
|
|
foreach (split(/\s+/, $HOSTS{$host}{ignore})) {
|
|
$ignore{$_} = 1;
|
|
}
|
|
|
|
## exec method
|
|
if ($HOSTS{$host}{method} eq 'exec') {
|
|
unless (defined $HOSTS{$host}{execcommand}) {
|
|
die "execcommand not specified for $host, skipping...";
|
|
}
|
|
%results = get_exec_results($HOSTS{$host}{execcommand}, "$rrdlocation$host.txt");
|
|
|
|
## Network socket connection method
|
|
} elsif ($HOSTS{$host}{method} eq 'connect') {
|
|
unless (defined $HOSTS{$host}{hostname}) {
|
|
die "hostname not specified for $host, skipping...";
|
|
}
|
|
my $port = $HOSTS{$host}{port} || $defaultport;
|
|
%results = get_net_results($HOSTS{$host}{hostname}, $port, "$rrdlocation$host.txt");
|
|
|
|
## Unknown method
|
|
} else {
|
|
die "Unknown method specified for $host, skipping...";
|
|
}
|
|
|
|
## Simple check that we've got reasonable statgrab data
|
|
unless ($results{const}{0} eq '0') {
|
|
die "Bad statgrab results";
|
|
} else {
|
|
print "got result for $host\n";
|
|
}
|
|
|
|
## Update RRDs
|
|
foreach ('cpu', 'load', 'mem', 'page', 'proc', 'user', 'swap') {
|
|
unless (-e "$rrdlocation$host.$_.rrd") {
|
|
create_rrd($rrdlocation, $_, $host, '');
|
|
}
|
|
}
|
|
update_rrd("$rrdlocation$host.cpu.rrd", sprintf("N:%s:%s:%s:%s:%s:%s:%s",
|
|
$results{cpu}{idle},
|
|
$results{cpu}{iowait},
|
|
$results{cpu}{kernel},
|
|
$results{cpu}{nice},
|
|
$results{cpu}{swap},
|
|
$results{cpu}{total},
|
|
$results{cpu}{user}));
|
|
|
|
update_rrd("$rrdlocation$host.load.rrd", sprintf("N:%s:%s:%s",
|
|
$results{load}{min1},
|
|
$results{load}{min5},
|
|
$results{load}{min15}));
|
|
|
|
update_rrd("$rrdlocation$host.mem.rrd", sprintf("N:%s:%s:%s:%s",
|
|
$results{mem}{cache},
|
|
$results{mem}{free},
|
|
$results{mem}{total},
|
|
$results{mem}{used}));
|
|
|
|
update_rrd("$rrdlocation$host.page.rrd", sprintf("N:%s:%s",
|
|
$results{page}{in},
|
|
$results{page}{out}));
|
|
|
|
update_rrd("$rrdlocation$host.proc.rrd", sprintf("N:%s:%s:%s:%s:%s",
|
|
$results{proc}{running},
|
|
$results{proc}{sleeping},
|
|
$results{proc}{stopped},
|
|
$results{proc}{total},
|
|
$results{proc}{zombie}));
|
|
|
|
update_rrd("$rrdlocation$host.user.rrd", sprintf("N:%s",
|
|
$results{user}{num}));
|
|
|
|
update_rrd("$rrdlocation$host.swap.rrd", sprintf("N:%s:%s:%s",
|
|
$results{swap}{free},
|
|
$results{swap}{total},
|
|
$results{swap}{used}));
|
|
|
|
## net device RRDs
|
|
foreach my $dev (keys %{ $results{net} }) {
|
|
unless (defined $ignore{"net.$dev"}) {
|
|
unless (-e "$rrdlocation$host.net.$dev.rrd") {
|
|
create_rrd($rrdlocation, 'net', $host, $dev);
|
|
}
|
|
update_rrd("$rrdlocation$host.net.$dev.rrd", sprintf("N:%s:%s:%s:%s:%s:%s",
|
|
$results{net}{$dev}{rx} || 0,
|
|
$results{net}{$dev}{tx} || 0,
|
|
$results{net}{$dev}{ipackets} || 0,
|
|
$results{net}{$dev}{opackets} || 0,
|
|
$results{net}{$dev}{ierrors} || 0,
|
|
$results{net}{$dev}{oerrors} || 0));
|
|
}
|
|
}
|
|
|
|
## disk device RRDs
|
|
foreach my $dev (keys %{ $results{disk} }) {
|
|
unless (defined $ignore{"disk.$dev"}) {
|
|
unless (-e "$rrdlocation$host.disk.$dev.rrd") {
|
|
create_rrd($rrdlocation, 'disk', $host, $dev);
|
|
}
|
|
update_rrd("$rrdlocation$host.disk.$dev.rrd", sprintf("N:%s:%s",
|
|
$results{disk}{$dev}{read_bytes},
|
|
$results{disk}{$dev}{write_bytes}));
|
|
}
|
|
}
|
|
|
|
## fs device RRDs
|
|
foreach my $dev (keys %{ $results{fs} }) {
|
|
unless (defined $ignore{"fs.$dev"}) {
|
|
unless (-e "$rrdlocation$host.fs.$dev.rrd") {
|
|
create_rrd($rrdlocation, 'fs', $host, $dev);
|
|
}
|
|
update_rrd("$rrdlocation$host.fs.$dev.rrd", sprintf("N:%s:%s:%s:%s",
|
|
$results{fs}{$dev}{used},
|
|
$results{fs}{$dev}{size},
|
|
$results{fs}{$dev}{used_inodes},
|
|
$results{fs}{$dev}{total_inodes}));
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
# parent process needs to preside over the death of its kids
|
|
while ( my $kid = shift @kids ) {
|
|
my $reaped = waitpid( $kid, 0 );
|
|
unless ( $reaped == $kid ) {
|
|
warn "Something's up: $?\n";
|
|
}
|
|
}
|
|
}
|