File check_iostat of Package monitoring-plugins-sar-perf

#!/usr/bin/perl

#
# Version 0.0.2 - Jan/2009
# Changes: added device verification
#
# by Thiago Varela - thiago@iplenix.com

# Version 0.1 - Nov/2011
# by Ruediger Oertel ro@suse.de
# Changes:
#     - rewrite in perl, no need for external grep, awk, bc
#     - add output for iowait
#     - implement using device mapper names, e.g. $vg-$lv

use strict;
use Getopt::Std;

$Getopt::Std::STANDARD_HELP_VERSION = "true";

my $iostat = `which iostat 2>/dev/null`;
chomp($iostat);

my $progname = $0;


# call it VERSION_MESSAGE so that getopts uses it automatically
sub VERSION_MESSAGE {
    print "$progname: version 0.1, Nov/2011\n";
}

# call it HELP_MESSAGE so that getopts uses it automatically
sub HELP_MESSAGE {
    print "\n\tThis plugin shows the I/O usage of the specified disk, using the iostat external program.\n";
    print "\tIt prints three statistics: Transactions per second (tps), Kilobytes per second\n";
    print "read from the disk (KB_read/s) and and written to the disk (KB_written/s)\n\n";
    print "$progname:\n\t-d <disk>\t\tDevice to be checked (without the full path, eg. sda)\n";
    print "\t\t\t\t(also accepted are device mapper names)\n";
    print "\t-c <tps>,<read>,<wrtn>\tSets the CRITICAL level for tps, KB_read/s and KB_written/s, respectively\n";
    print "\t-w <tps>,<read>,<wrtn>\tSets the WARNING level for tps, KB_read/s and KB_written/s, respectively\n";
    print "\t-C <percent>\t Sets the CRITICAL level for iowait\n";
    print "\t-W <percent>\t Sets the WARNING level for iowait\n";
    print "\t-X <percent>\t Sets the CRITICAL level for utilization\n";
    print "\t-Y <percent>\t Sets the WARNING level for utilization\n";
    print "\t\t\t(if no level is set for iowait, no warning is set for this value)\n";
    exit 1;
}

unless ($iostat && -f $iostat) {
    warn "ERROR: You must have iostat installed in order to run this plugin\n";
    exit 1;
}

# Getting parameters:
my %opts;
getopts('d:w:c:W:C:X:Y:hv', \%opts);

my $disk = $opts{'d'};
my $warning = $opts{'w'};
my $critical = $opts{'c'};
my $warn_iowait = $opts{'W'};
my $crit_iowait = $opts{'C'};
my $warn_util = $opts{'X'};
my $crit_util = $opts{'Y'};

VERSION_MESSAGE() if $opts{'v'};
HELP_MESSAGE() if $opts{'h'};

# Adjusting the three warn and crit levels:
my ($crit_tps,$crit_read,$crit_written) = split(',',$critical);
my ($warn_tps,$warn_read,$warn_written) = split(',',$warning);

# Checking parameters:
if (-d "$disk") {
    # directory specified ...
    my $mp = `stat --format '\%m' $disk`;
    chomp($mp);
    my $fstype = `stat --file-system --format '\%T' $mp`;
    chomp($fstype);
    if ($fstype eq "tmpfs") {
        print "OK - $disk (mountpoint $mp is tmpfs)\n";
        exit 0;
    }
    open(MOUNTS,"/proc/mounts");
    while(<MOUNTS>) {
        chomp($_);
        my @line = split('\s+',$_);
        $disk = $line[0] if $mp eq $line[1]; 
    }
    close(MOUNTS);
}

$disk =~ s/^\/dev\/mapper\///;
$disk =~ s/^\/dev\///;

if (! -b "/dev/$disk") {
    if (-b "/dev/mapper/$disk") {
        my @f = stat("/dev/mapper/$disk");
        $f[6] %= 256;
        $disk = "dm-$f[6]";
    } else {
        warn "ERROR: Device incorrectly specified\n";
        HELP_MESSAGE();
    }
}

unless ($warn_tps && $warn_read && $warn_written && $crit_tps && $crit_read && $crit_written) {
    warn "ERROR: You must specify all warning and critical levels\n";
    HELP_MESSAGE();
}

if ($warn_tps > $crit_tps || $warn_read > $crit_read || $warn_written > $crit_written) {
    warn "ERROR: critical levels must be highter than warning levels\n";
    HELP_MESSAGE();
}

if ($warn_iowait && $crit_iowait && $warn_iowait > $crit_iowait) {
    warn "ERROR: critical iowait level must be higher than warning level\n";
    HELP_MESSAGE();
}

if ($warn_util && $crit_util && $warn_util > $crit_util) {
    warn "ERROR: critical utilization level must be higher than warning level\n";
    HELP_MESSAGE();
}

my ($tps,$rps,$wps,$kbread,$kbwritten,$iowait,$util);
my $seen_usage = 0;
my $seen_disk = 0;
my $field_rps = 3;
my $field_wps = 4;
my $field_rmbps = 5;
my $field_wmbps = 6;
my $field_util = 13;

# Doing the actual check:
open (IOSTAT,"-|","$iostat -kx $disk 5 2");
while (<IOSTAT>) {
    chomp();
    if (/^[0-9\.\ \t]+$/) {
	$seen_usage++;
	next if $seen_usage < 2;
	my (@stats) = split ('\s+', $_);
        $iowait = $stats[4];
        next;
    }
    if (/^Device/) {
	my @hdrs = split('\s+', $_);
	my ($search_rps) = grep { $hdrs[$_] eq "r/s" } 0..$#hdrs;
	$field_rps = $search_rps if $search_rps;
	my ($search_wps) = grep { $hdrs[$_] eq "w/s" } 0..$#hdrs;
	$field_wps = $search_wps if $search_wps;
	my ($search_rmbps) = grep { $hdrs[$_] eq "rkB/s" } 0..$#hdrs;
	$field_rmbps = $search_rmbps if $search_rmbps;
	my ($search_wmbps) = grep { $hdrs[$_] eq "wkB/s" } 0..$#hdrs;
	$field_wmbps = $search_wmbps if $search_wmbps;
	my ($search_util) = grep { $hdrs[$_] eq "%util" } 0..$#hdrs;
	$field_util = $search_util if $search_util;
	next;
    }
    if (/^$disk /) {
	$seen_disk++;
	next if $seen_disk < 2;
	my (@stats) = split ('\s+', $_);
        ($rps,$wps,$kbread,$kbwritten,$util) = @stats[$field_rps,$field_wps,$field_rmbps,$field_wmbps,$field_util];
	$tps = $rps + $wps;
	last;
    }
}
close (IOSTAT);    

my $msg = "OK";
my $status = 0;
my %reasons;

# Comparing the result and setting the correct level:
if ($tps >= $warn_tps || $kbread >= $warn_read || $kbwritten >= $warn_written) {
   $msg = "WARNING";
   $reasons{'throughput'} = 1;
   $status = 1;
}

if ($warn_iowait && $iowait >= $warn_iowait) {
   $msg = "WARNING";
   $reasons{'iowait'} = 1;
   $status = 1;
}

if ($warn_util && $util >= $warn_util) {
   $msg = "WARNING";
   $reasons{'util'} = 1;
   $status = 1;
}

if ($tps >= $crit_tps || $kbread >= $crit_read || $kbwritten >= $crit_written) {
   $msg = "CRITICAL";
   $reasons{'throughput'} = 2;
   $status = 2;
}

if ($crit_iowait && $iowait >= $crit_iowait) {
   $msg = "CRITICAL";
   $reasons{'iowait'} = 2;
   $status = 2;
}

if ($crit_util && $util >= $crit_util) {
   $msg = "CRITICAL";
   $reasons{'util'} = 2;
   $status = 2;
}

$msg .= " (".join(",",keys(%reasons)).")" if $status != 0;

my $p_tps = $tps;
if ($warn_tps) {
   $p_tps .= ";$warn_tps";
   if ($crit_tps) {
      $p_tps .= ";$crit_tps";
   }
}
my $p_kbread = $kbread;
if ($warn_read) {
   $p_kbread .= ";$warn_read";
   if ($crit_read) {
      $p_kbread .= ";$crit_read";
   }
}
my $p_kbwritten = $kbwritten;
if($warn_written) {
   $p_kbwritten .= ";$warn_written";
   if ($crit_written) {
      $p_kbwritten .= ";$crit_written";
   }
}
my $p_iowait = $iowait;
if ($warn_iowait) {
   $p_iowait .= ";$warn_iowait";
   if ($crit_iowait) {
      $p_iowait .= ";$crit_iowait";
   }
}
my $p_util = $util;
if ($warn_util) {
   $p_util .= ";$warn_util";
   if ($crit_util) {
      $p_util .= ";$crit_util";
   }
}
# Printing the results:
print "$msg - I/O stats tps=$tps KB_read/s=$kbread KB_written/s=$kbwritten iowait=$iowait util=$util | 'tps'=$p_tps; 'KB_read/s'=$p_kbread; 'KB_written/s'=$p_kbwritten; 'iowait'=$p_iowait; 'util'=$p_util\n";

# Bye!
exit $status;
openSUSE Build Service is sponsored by