dnl $List(FREEBSD7): echo FREEBSD dnl $List(FREEBSD6): echo FREEBSD dnl $List(FREEBSD5): echo FREEBSD dnl $List(FREEBSD4): echo FREEBSD dnl $List(FREEBSD4): echo FREEBSD dnl $List(FREEBSD3): echo FREEBSD3 dnl $List(HPUX9): echo HPUX dnl $List(HPUX9): echo HPUX dnl $List(SLACK): echo SLACK dnl $List(LINUX): echo LINUX dnl $List(AS2): echo LINUX dnl $List(AS3): echo LINUX dnl $List(AS4): echo LINUX dnl $List(SUN5): echo SOL8 dnl $List(SOL8): echo SOL8 dnl $List(SOL9): echo SOL8 dnl $List(SOL10): echo SOL8 dnl $List(IBMR2): echo IBMR2 dnl $List(AIX): echo IBMR2 dnl $List(*): %;%. changequote(,)dnl #!/usr/bin/env perl # $Id: unixstats.pl.host,v 2.11 2008/12/12 22:01:21 tswan Exp $ # use lib '/usr/local/lib/sac/perl'.join('.', unpack('c*', $^V)), '/usr/local/lib/sac'; use strict; use Socket; use Sys::Hostname; use Getopt::Std; use POSIX qw(floor); my($progname) = $0; $progname ||= 'unixstats'; $progname = $1 if $progname =~ m,.*/(.+)$,o; my(%opts); getopts('dN:hH:p:S:T:O:Vx', \%opts); # ZZZ configure here is you want a default suffix added to your # plain hostname my($suffix) ||= $opts{'S'}; # e.g. "prod", or "lab", or "test" my($common) = $opts{'T'}; $common ||= "fedex.com"; # common tail to remove my($admindept) = $opts{'O'}; $admindept ||= "sac"; # admin default department # RRD update interval must be >= 10 sec, or we move the load too much --ksb my($stall,$remainder); # Under -p (persistant) we are a service run at boot, otherwise assume we # are run from cron once a minute or so, or the command line -x to test. if ($opts{'p'}) { if ($opts{'p'} < 10) { $opts{'p'} = 10; } $stall = $opts{'x'} ? 0 : floor(0.5+rand($opts{'p'})); $remainder = $opts{'p'}-$stall; } else { $stall = $opts{'x'} ? 0 : floor(3.5+rand(55)); $remainder = undef; } # get hostname: CONFIG for your domain, not ".fedex.com" and ".sac" my($host) = hostname(); ifdef(FORCE_LOCAL_DOMAIN,  $host =~ m/([^.]*)\..*$/o and do { $host = $1; }; $host .= "FORCE_LOCAL_DOMAIN"; , $host =~ m/(.*)\.$common$/ and do { $host = $1; $host =~ m/(.*)\.$admindept$/ and do { $host = $1; }; }; )dnl  # If our hostname is not a FQDN under $common we might have to adjust the # results from the above. Or just force it on the command line with # -N real-name. $host .= ".$suffix" if ($suffix && $suffix ne $admindept); $opts{'N'} ||= $opts{'n'}; # backwards compatibility with old Linix $host = $opts{'N'} if ($opts{'N'}); my($peghost) = shift(@ARGV); $peghost ||= $opts{'H'}; # backwards compatible with HPUX my($pegport); $peghost ||= 'peg.sac.fedex.com:31415'; if ($peghost =~ m/^([^:]+):([0-9]+)$/) { $pegport = $2; $peghost = $1; } if ($peghost =~ m/^:([0-9]+)$/) { $pegport = $1; } $pegport ||= 31415; if ($opts{'V'}) { print "$progname: ", '$Id: unixstats.pl.host,v 2.11 2008/12/12 22:01:21 tswan Exp $', "\n", "update: $peghost:$pegport\n", "node: $host", ($opts{'N'} ? " [forced]": ''), "\n"; if (defined($admindept) && defined($common)) { print "remove: admin \"$admindept\" after toplevel \"$common\"\n"; } elsif (defined $common) { print "remove: toplevel \"$common\"\n"; } elsif (defined $admindept) { print "squelch: admin \"$admindept\"\n"; } if (defined($suffix) && (!defined $admindept || $suffix ne $admindept)) { print "add: suffix $suffix\n"; } if (defined $remainder) { print "updates: every ", $stall+$remainder, ", at offset $stall\n"; } else { print "update: once, stalling for $stall\n"; } exit(0); } if ($opts{'h'}) { print "$progname: usage [-dx] [-p delay] [-N node] [-O admin] [-S suffix] [-T toplevel] [peg][:port]\n", "$progname: -h|-V\n", "d display RRD path only, and exit\n", "h output a brief help message\n", "N node use this node name, rather than our hostname\n", "O admin set the administrators department suffix\n", "p delay update persistantly, about every delay seconds\n", "S suffix remove this suffix after toplevel, if present\n", "T toplevel remove this from the end of our hostname\n", "V output the standard version information\n", "x trace updates on stdout\n", "peg sample collection host, running rrdd\n", "port rrdd update port (otherwise $pegport)\n"; exit(0); } sub mkUpdate() { ifelse(yes,ifelse(HOSTTYPE,SUN5,yes,HOSTTYPE,SOL8,yes,HOSTTYPE,SOL9,yes,HOSTTYPE,SOL10,yes,no), # the Solaris specific part, gather the stats my(%s) = (); my($key, $line); # get 1-minute load average my($value) = `/usr/bin/uptime`; ($s{'sysload'}) = ($value =~ m/average:\s+([0-9.]+),/); # get what we can from vmstat open(VMSTAT, "/usr/bin/vmstat -s|") || die "popen: vmstat: $!"; while ($line = ) { chomp $line; ($value,$key) = $line =~ m/^\s*([0-9]+)\s+(.*)$/o; for ($key) { m/^pages paged in/ and do { $s{'pagein'} = $value; }; m/^pages paged out/ and do { $s{'pageout'} = $value; }; m/^user\s+cpu/ and do { $s{'cpu_user'} = $value; }; m/^system\s+cpu/ and do { $s{'cpu_sys'} = $value; }; m/^idle\s+cpu/ and do { $s{'cpu_idle'} = $value; }; m/^wait\s+cpu/ and do { $s{'cpu_wait'} = $value; }; m/^system\s+cpu/ and do { $s{'cpu_sys'} = $value; }; m/^device\s+interrupts/ and do { $s{'intr'} = $value; }; m/^system\s+calls/ and do { $s{'scall'} = $value; }; m/^cpu\s+context\s+switches/ and do { $s{'cswitch'} = $value; }; m/^forks/ and do { $s{'fork'} = $value; }; } } close(VMSTAT); return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); ,yes,ifelse(HOSTTYPE,FREEBSD,yes,HOSTTYPE,FREEBSD3,yes,HOSTTYPE,FREEBSD7,yes,HOSTTYPE,FREEBSD6,yes,HOSTTYPE,FREEBSD5,yes,HOSTTYPE,FREEBSD4,yes,no), # FreeBSD any stats my(%s) = (); my($line,$key,$value); # N.B. order is important here, new ones ON THE END because sysctl # stops at the first unknown one. Or spend a little more CPU # and put in "apply " in front of the command -- ksb open(SCTL, "/sbin/sysctl hw.ncpu vm.loadavg vm.stats.vm.v_swapin vm.stats.vm.v_vnodein vm.stats.vm.v_swapout vm.stats.vm.v_vnodeout vm.stats.sys.v_intr vm.stats.sys.v_syscall vm.stats.sys.v_swtch vm.stats.vm.v_forks kern.cp_time 2>/dev/null|") || die "popen: sysctl: $!"; my(%v) = (); while ($line = ) { chomp $line; ($key,$value) = split(': ', $line); $v{$key} ||= $value; } close(SCTL); if (exists($v{'vm.loadavg'})) { $s{'sysload'} = (split(' ',$v{'vm.loadavg'}))[1]; } else { my($sysload) = `/usr/bin/uptime`; chomp($sysload); $s{'sysload'} =~ s/.*average[s:]\s*\([0-9.]*\),.*/$1/o; } # To get this w/o sysctl we need to run an iostat -C -w ... to # read the cpu percentages (rounded to ints) from iostat, that's # too much work for integer approximations. So we fake it from # the number of CPUs and the load average. Better'n nada. --ksb if (exists($v{'kern.cp_time'})) { ($s{'cpu_user'}, $s{'cpu_nice'}, $s{'cpu_sys'}, $s{'cpu_int'}, $s{'cpu_idle'}) = split(' ', $v{'kern.cp_time'}); } if (exists($v{'vm.stats.vm.v_swapin'}) || exists($v{'vm.stats.vm.v_vnodein'})) { $s{'pagein'} = 0+$v{'vm.stats.vm.v_swapin'}+$v{'vm.stats.vm.v_vnodein'}; } if (exists($v{'vm.stats.vm.v_swapout'}) || exists($v{'vm.stats.vm.v_vodeout'})) { $s{'pageout'} = 0+$v{'vm.stats.vm.v_swapout'}+$v{'vm.stats.vm.v_vnodeout'}; } if (exists($v{'vm.stats.sys.v_intr'})) { $s{'intr'} = $v{'vm.stats.sys.v_intr'}; } if (exists($v{'vm.stats.sys.v_syscall'})) { $s{'scall'} = $v{'vm.stats.sys.v_syscall'}; } if (exists($v{'vm.stats.sys.v_swtch'})) { $s{'cswitch'} = $v{'vm.stats.sys.v_swtch'}; } if (exists($v{'vm.stats.vm.v_forks'})) { $s{'fork'} = $v{'vm.stats.vm.v_forks'}; } return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); ,HOSTTYPE,LINUX, # Linux common my(%s) = (); my($line,$key,$value); my($softint,$sysload); # get 1-minute load average if (open(UPTIME, "; chomp($sysload); $sysload =~ s/\s+.*//; close(UPTIME); } else { $sysload = `/usr/bin/uptime`; chomp($sysload); $sysload =~ s/.*average:\s*\([0-9.]*\),.*/$1/o; } $s{'sysload'} = $sysload if ('' ne $sysload);  ifelse(eval(HOSTOS < 40000),1, # RHEL3- # find the rest in /proc/stat open(STAT, ") { chomp $line; ($key,$value) = $line =~ m/^(\S+)\s+(.*)$/o; $key =~ s/:$//; for ($key) { m/^cpu$/ and do { ($s{'cpu_user'}, $s{'cpu_nice'}, $s{'cpu_sys'}, $s{'cpu_idle'}, $s{'cpu_wait'}, $s{'cpu_int'}, $softint) = split(/\s+/,$value); next; }; m/^page$/ and do { ($s{'pagein'}, $s{'pageout'}) = split(/\s+/,$value); next; }; m/^intr$/ and do { ($s{'intr'}) = split(/\s+/,$value); next; }; m/^processes$/ and do { $s{'fork'} = $value; next; }; m/^ctxt$/ and do { $s{'cswitch'} = $value; next; }; } } close(STAT); # Older versions of Linux don't have some fields. # Don't report them if they are undefinded. --jad delete $s{'cpu_wait'} unless (defined $s{'cpu_wait'}); if (defined $s{'cpu_int'}) { $softint ||= 0; $s{'cpu_int'} += $softint; } else { delete $s{'cpu_int'}; } , # RHEL 4+ # vmstat -s is provided to grab page in/out events. These were removed # from /proc/stat in later 2.4/2.6 kernels. open(VMSTAT, "/usr/bin/vmstat -s|") || die "open: vmstat: $!"; while ($line = ) { ($value,$key) = $line =~ m/^\s*([0-9]+)\s+(.*)$/o; for ($key) { m/^pages\s+paged\s+in/ and do { $s{'pagein'} = $value; }; m/^pages\s+paged\s+out/ and do { $s{'pageout'} = $value; }; m/^non-nice\s+user\s+cpu/ and do { $s{'cpu_user'} = $value; }; m/^nice\s+user\s+cpu/ and do { $s{'cpu_nice'} = $value; }; m/^system\s+cpu/ and do { $s{'cpu_sys'} = $value; }; m/^idle\s+cpu/ and do { $s{'cpu_idle'} = $value; }; m/^wait\s+cpu/i and do { $s{'cpu_wait'} = $value; }; m/^interrupts$/ and do { $s{'intr'} = $value; }; m/^cpu\s+context\s+switches/i and do { $s{'cswitch'} = $value; }; m/^forks/ and do { $s{'fork'} = $value; }; } } ) return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); ,HOSTTYPE,SLACK, # slackware version, largely untested -- ksb my(%s); my($line); # get 1-minute load average my($sysload); if (open(UPTIME, "; chomp($sysload); $sysload =~ s/\s+.*//; close(UPTIME); } else { $sysload = `/usr/bin/uptime`; chomp($sysload); $sysload =~ s/.*average:\s*\([0-9.]*\),.*/$1/o; } $s{'sysload'} = $sysload if ('' ne $sysload); # rumage for the others we might find in /proc/stat open(PSTAT, ") { chomp($line); if ($line =~ m/^cpu\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/o) { $s{'cpu_user'} = $1; $s{'cpu_nice'} = $2; $s{'cpu_sys'} = $3; $s{'cpu_idle'} = $4; # XXX missing intr here next; } if ($line =~ m/^page\s*(\d*)\s*(\d+)\s*$/o) { $s{'pagein'} = $1; $s{'pageout'} = $2; next; } if ($line =~ m/^intr\s+(\d*)/o) { $s{'intr'} = $1; next; } if ($line =~ m/^ctxt\s+(\d*)/o) { $s{'cswitch'} = $1; next; } if ($line =~ m/^processes\s+(\d*)/o) { $s{'fork'} = $1; next; } } close(PSTAT); return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); ,HOSTTYPE,IBMR2, my(%s) = (); my($line,$key,$value); # get 1-minute load average $value = `/usr/bin/uptime`; ($s{'sysload'}) = ($value =~ /average:\s+([0-9.]+),/); open(VMSTAT, "/usr/bin/vmstat -s ; /usr/bin/vmstat -f|") || die "popen: vmstat: $!"; while ($line = ) { chomp $line; ($value,$key) = $line =~ m/^\s*([0-9]+)\s+(.*)$/o; for ($key) { m/^page ins/ and do { $s{'pagein'} = $value; }; m/^page outs/ and do { $s{'pageout'} = $value; }; m/^syscalls*/ and do { $s{'scall'} = $value; }; m/^cpu\s+context\s+switches/ and do { $s{'cswitch'} = $value; }; m/^device\s+interrupts/ and do { $s{'intr'} = $value; }; m/^forks/ and do { $s{'fork'} = $value; }; } } close(VMSTAT); open(IOSTAT, "/usr/bin/iostat -t|tail -1|") || die "popen: iostat: $!"; #tty: tin tout avg-cpu: % user % sys % idle % iowait # 0.0 2.1 0.1 0.5 98.3 1.0 # XXX: multiply by the number of on-line CPUs on the host, really my(@cpu) = split(/\s+/, ); $s{'cpu_user'} = $cpu[2]; $s{'cpu_sys'} = $cpu[3]; $s{'cpu_idle'} = $cpu[4]; $s{'cpu_wait'} = $cpu[5]; close(IOSTAT); return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); ,yes,ifelse(HOSTTYPE,HPUX,yes,HOSTTYPE,HPUX9,yes,HOSTTYPE,HPUX10,yes,no), # HPUX9 (and maybe 10?) unix collection -- ksb my(%s) = (); my($line,$key,$value); # get 1-minute load average $value = `/usr/bin/uptime`; ($s{'sysload'}) = ($value =~ /average:\s+([0-9.]+),/); open(VMSTAT, "/usr/bin/vmstat -f ; /usr/bin/vmstat -s|") || die "popen: vmstat: $!"; while ($line = ) { chomp $line; ($value,$key) = $line =~ m/^\s*([0-9]+)\s+(.*)$/o; for ($key) { m/^pages paged in/ and do { $s{'pagein'} = $value; next; }; m/^pages paged out/ and do { $s{'pageout'} = $value; next; }; m/^user\s*cpu/o and do { $s{'cpu_user'} = $1; next; }; m/^system\s*cpu/o and do { $s{'cpu_sys'} = $1; next; }; m/^idle\s*cpu/o and do { $s{'cpu_idle'} = $1; next; }; m/^wait\s*cpu/o and do { $s{'cpu_wait'} = $1; next; }; m/^system\s*cpu/o and do { $s{'cpu_sys'} = $1; next; }; m/^nice\s*cpu/o and do { $s{'cpu_nice'} = $1; next; }; m/^device\s*interrupts/o and do { $s{'intr'} = $1; next; }; m/^system\s*calls/o and do { $s{'scall'} = $1; next; }; m/^cpu\s*context\s*switches/o and do { $s{'cswitch'} = $1; next; }; m/^forks,.*/o and do { $s{'fork'} = $1; next; }; m/^forks/o and do { $s{'fork'} = $1; next; }; } } close(VMSTAT); return "host/$host/unix.rrd ".join(':',keys(%s)).' N:'.join(':',values(%s)); , # we don't have a host part die "unixstats make update: unkown type HOSTTYPE"; ) } # Send to peg's rrdd, peg could move over time, so we look up up my($update,$ipout,$proto,$sockaddr); $proto = getprotobyname('udp'); socket(SOCKET, PF_INET, SOCK_DGRAM, $proto) || die "socket: inet: $!"; while ($ipout = inet_aton($peghost)) { sleep($stall); $update = mkUpdate(); if ($opts{'d'}) { $update =~ s/\s.*//; print "$update\n"; last; } print $update, "\n" if ($opts{'x'}); $sockaddr = sockaddr_in($pegport, $ipout); send(SOCKET, "00 ".$update, 0, $sockaddr); last unless defined($remainder); sleep($remainder); next unless (0 == $stall); # -x set stall to 0, recompute it $stall = floor(0.5+rand($opts{'p'})); $remainder = $opts{'p'}-$stall; } close(SOCKET); exit(0); dnl changequote(`,')dnl