2008-01-01 18:18:06 +01:00
|
|
|
#!/usr/bin/perl -w
|
|
|
|
#
|
|
|
|
# Plugin for watching io-bound traffic (in blocks) on disks.
|
|
|
|
#
|
|
|
|
# Usage: Link or copy into /etc/lrrd/client.d/
|
|
|
|
#
|
|
|
|
# Parameters:
|
|
|
|
#
|
|
|
|
# config (required)
|
|
|
|
# autoconf (optional - used by lrrd-config)
|
|
|
|
#
|
|
|
|
# $Log$
|
|
|
|
# Revision 1.14 2004/12/10 18:51:44 jimmyo
|
|
|
|
# linux/apt* has been forced to LANG=C, to get predictable output.
|
|
|
|
#
|
|
|
|
# Revision 1.13 2004/12/10 10:47:49 jimmyo
|
|
|
|
# Change name from ${scale} to ${graph_period}, to be more consistent.
|
|
|
|
#
|
|
|
|
# Revision 1.12 2004/12/09 22:12:56 jimmyo
|
|
|
|
# Added "graph_period" option, to make "graph_sums" usable.
|
|
|
|
#
|
|
|
|
# Revision 1.11 2004/11/21 00:17:12 jimmyo
|
|
|
|
# Changed a lot of plugins so they use DERIVE instead of COUNTER.
|
|
|
|
#
|
|
|
|
# Revision 1.10 2004/11/20 23:58:22 jimmyo
|
|
|
|
# The linux/iostat plugin now ignores devices without traffic (Deb#267195).
|
|
|
|
#
|
|
|
|
# Revision 1.9 2004/09/25 22:29:16 jimmyo
|
|
|
|
# Added info fields to a bunch of plugins.
|
|
|
|
#
|
|
|
|
# Revision 1.8 2004/08/24 13:37:29 ilmari
|
|
|
|
# Add total line
|
|
|
|
#
|
|
|
|
# Revision 1.7 2004/05/20 13:57:12 jimmyo
|
|
|
|
# Set categories to some of the plugins.
|
|
|
|
#
|
|
|
|
# Revision 1.6 2004/02/02 18:18:07 jimmyo
|
|
|
|
# Changed to an informative vlabel, since the field.label information has been made shorter.
|
|
|
|
#
|
|
|
|
# Revision 1.5 2004/02/02 17:52:32 jimmyo
|
|
|
|
# Linux/iostat now shows only disks also on machines without devfs.
|
|
|
|
#
|
|
|
|
# Revision 1.4 2004/02/02 16:54:38 jimmyo
|
|
|
|
# Make the iostat plugin work properly.
|
|
|
|
#
|
|
|
|
# Revision 1.3 2004/02/02 16:53:53 jimmyo
|
|
|
|
# Make the iostat plugin work properly.
|
|
|
|
#
|
|
|
|
# Revision 1.2 2004/01/31 19:24:52 jimmyo
|
|
|
|
# Rewrite of linux/iostat by Mike Fedyk (Deb##223373,224113).
|
|
|
|
#
|
|
|
|
# Revision 1.1 2004/01/02 18:50:01 jimmyo
|
2014-12-05 00:37:42 +01:00
|
|
|
# Renamed occurrences of lrrd -> munin
|
2008-01-01 18:18:06 +01:00
|
|
|
#
|
|
|
|
# Revision 1.1.1.1 2004/01/02 15:18:07 jimmyo
|
|
|
|
# Import of LRRD CVS tree after renaming to Munin
|
|
|
|
#
|
|
|
|
# Revision 1.5 2003/12/18 18:09:32 jimmyo
|
|
|
|
# Added total line
|
|
|
|
#
|
|
|
|
# Revision 1.4 2003/12/18 11:01:51 jimmyo
|
|
|
|
# Fix by_dev compare issue.
|
|
|
|
#
|
|
|
|
# Revision 1.3 2003/12/16 17:51:08 jimmyo
|
|
|
|
# Plugin linux/iostat modified. Now runs on 2.6, and now "mirrors" i/o like eth* et al. (Deb#224113, Deb#223373)
|
|
|
|
#
|
|
|
|
# Revision 1.2 2003/11/07 17:43:16 jimmyo
|
|
|
|
# Cleanups and log entries
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# Magic markers (optional - used by lrrd-config and some installation
|
|
|
|
# scripts):
|
|
|
|
#
|
|
|
|
#%# family=auto
|
|
|
|
#%# capabilities=autoconf
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Data::Dumper;
|
|
|
|
|
|
|
|
# Where to get stats from
|
|
|
|
my $detailed_present = 0;
|
|
|
|
my $stat_present = 0;
|
|
|
|
# And md things here?
|
|
|
|
my $mdstat_present = 0;
|
|
|
|
|
|
|
|
if ( (-f '/proc/diskstats') or
|
|
|
|
(system("grep -q 'rio rmerge rsect ruse wio wmerge wsect wuse running use aveq' /proc/partitions") == 0) ) {
|
|
|
|
$detailed_present = 1;
|
|
|
|
} elsif (system("grep -q '^disk_io: [^ ]' /proc/stat") == 0) {
|
|
|
|
$stat_present = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
$mdstat_present = -f '/proc/mdstat';
|
|
|
|
|
|
|
|
if ( defined($ARGV[0]) and $ARGV[0] eq "autoconf") {
|
|
|
|
if ($mdstat_present and ($detailed_present or $stat_present)) {
|
|
|
|
print "yes\n";
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
print "no\n";
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
my %devs;
|
|
|
|
my %nametodev;
|
|
|
|
|
|
|
|
if ($detailed_present) {
|
|
|
|
&fetch_detailed;
|
|
|
|
} elsif ($stat_present) {
|
|
|
|
# Falling back to /proc/stat
|
|
|
|
&fetch_stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $md = $0;
|
|
|
|
$md =~ s/.*_//;
|
|
|
|
|
|
|
|
open(MD,"/proc/mdstat");
|
|
|
|
|
|
|
|
my ($dev,$mdstatus,$raid,@devs);
|
|
|
|
|
|
|
|
while (<MD>) {
|
|
|
|
next unless /^$md/o;
|
|
|
|
($dev, $mdstatus) = split(/\s+:\s+/,$_,2);
|
|
|
|
($mdstatus, $raid, @devs) = split(/\s+/,$mdstatus);
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
|
|
|
|
# print "DEVICES: ",join(', ',@devs),"\n";
|
|
|
|
|
|
|
|
# Remove unwanted things like raid device number, partition number
|
|
|
|
# and sort nicely.
|
|
|
|
@devs = sort by_dev map { s/\d*\[.*\]$//; $_; } @devs;
|
|
|
|
|
|
|
|
# Insert the raid device into the mix.
|
|
|
|
unshift(@devs,$md);
|
|
|
|
|
|
|
|
# And translate to the device name used by the datastructures.
|
|
|
|
@devs = map { $nametodev{$_}; } @devs;
|
|
|
|
|
|
|
|
close(MD);
|
|
|
|
my $i=0;
|
|
|
|
|
|
|
|
if ( $ARGV[0] and $ARGV[0] eq "config") {
|
|
|
|
print "graph_title IOstat for $md\n";
|
|
|
|
print "graph_args --base 1024 -l 0\n";
|
|
|
|
print "graph_vlabel blocks / \${graph_period} read (-) / written (+)\n";
|
|
|
|
print "graph_category disk\n";
|
|
|
|
print "graph_info This graph shows the I/O to and from block devices comprising the $raid device $md.\n";
|
|
|
|
|
|
|
|
my @grapho = @devs;
|
|
|
|
# The first shall be last
|
|
|
|
push(@grapho,shift(@grapho));
|
|
|
|
|
|
|
|
print "graph_order";
|
|
|
|
foreach my $key (@grapho) {
|
|
|
|
print " ", $key, "_read ", $key, "_write ";
|
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
foreach my $key (@devs) {
|
|
|
|
print $key . "_read.label $devs{$key}->{name}\n";
|
|
|
|
print $key . "_read.type DERIVE\n";
|
|
|
|
print $key . "_read.max 900000\n";
|
|
|
|
print $key . "_read.min 0\n";
|
|
|
|
print $key . "_read.graph no\n";
|
|
|
|
print $key . "_write.label $devs{$key}->{name}\n";
|
|
|
|
print $key . "_write.info I/O on device $devs{$key}->{name}\n";
|
|
|
|
print $key . "_write.type DERIVE\n";
|
|
|
|
print $key . "_write.max 900000\n";
|
|
|
|
print $key . "_write.min 0\n";
|
|
|
|
print $key . "_write.negative " . $key . "_read\n";
|
|
|
|
if ($i == 0) {
|
|
|
|
print "${key}_read.draw LINE2\n";
|
|
|
|
print "${key}_write.draw LINE2\n";
|
|
|
|
} elsif ($i == 1) {
|
|
|
|
print "${key}_read.draw AREA\n";
|
|
|
|
print "${key}_write.draw AREA\n";
|
|
|
|
} else {
|
|
|
|
print "${key}_read.draw STACK\n";
|
|
|
|
print "${key}_write.draw STACK\n";
|
|
|
|
}
|
|
|
|
$i++;
|
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# print Dumper \%nametodev;
|
|
|
|
# print Dumper \%devs;
|
|
|
|
|
|
|
|
foreach my $key (@devs) {
|
|
|
|
# print "Device name: $key, iostat name: ",$nametodev{$key},"\n";
|
|
|
|
print $key, "_read.value ", $devs{$key}->{rsect}, "\n";
|
|
|
|
print $key, "_write.value ", $devs{$key}->{wsect}, "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub by_dev {
|
|
|
|
return $a cmp $b;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub fetch_stat() {
|
|
|
|
open (IN, "/proc/stat") or die "Could not open /proc/stat for reading: $!\n";
|
|
|
|
|
|
|
|
while (<IN>) {
|
|
|
|
next unless (/^disk_io:\s*(.+)\s*/);
|
|
|
|
foreach my $dev (split /\s+/) {
|
|
|
|
next unless $dev =~ /\S/;
|
|
|
|
next unless ($dev =~ /\((\d+),(\d+)\):\(\d+,(\d+),(\d+),(\d+),(\d+)\)/);
|
|
|
|
|
|
|
|
my $name = "dev".$1."_".$2;
|
|
|
|
|
|
|
|
$nametodev{$name}=$name;
|
|
|
|
|
|
|
|
$devs{$name} = {
|
|
|
|
name => $name,
|
|
|
|
rio => $3,
|
|
|
|
rsect => $4,
|
|
|
|
wio => $5,
|
|
|
|
wsect => $6
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close (IN);
|
|
|
|
}
|
|
|
|
|
|
|
|
my %maj_count;
|
|
|
|
sub get_disk_count()
|
|
|
|
{
|
|
|
|
my @disk_count;
|
|
|
|
my $major = $_[0];
|
|
|
|
$maj_count{$major} = 0 unless exists($maj_count{$major});
|
|
|
|
$disk_count[0] = $maj_count{$major}++;
|
|
|
|
die "Could not find disk_count for major: $major" unless (exists($disk_count[0]));
|
|
|
|
return $disk_count[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub fetch_detailed() {
|
|
|
|
|
|
|
|
if (open(DETAILED, "/proc/diskstats")
|
|
|
|
or open(DETAILED, "/proc/partitions")) {
|
|
|
|
while (<DETAILED>) {
|
|
|
|
if (/^\s+(\d+)\s+\d+\s*\d*\s+([[:alpha:][:digit:]\/]+)\s+(.*)/) {
|
|
|
|
my @fields = split(/\s+/, $3);
|
|
|
|
my $tmpnam = $2;
|
|
|
|
my $major = $1;
|
|
|
|
if ($tmpnam =~ /^md\d+/) {
|
|
|
|
# That's fine, we want raid disks reported here.
|
|
|
|
} elsif ($tmpnam =~ /\d+$/ ) {
|
|
|
|
# Special case for devices like cXdXpX,
|
|
|
|
# like the cciss driver
|
|
|
|
next unless $tmpnam =~ /\/c\d+d\d+$/
|
|
|
|
}
|
|
|
|
next unless grep { $_ } @fields;
|
|
|
|
|
|
|
|
$tmpnam =~ s/\/[[:alpha:]]+(\d+)/\/$1/g;
|
|
|
|
$tmpnam =~ s/^([^\/]+)\//$1/;
|
|
|
|
$tmpnam =~ s/\/disc$//;
|
|
|
|
|
|
|
|
my $devnam = "dev".$major."_".&get_disk_count($major);
|
|
|
|
|
|
|
|
$nametodev{$tmpnam} = $devnam;
|
|
|
|
|
|
|
|
$devs{$devnam} = {
|
|
|
|
major => $major,
|
|
|
|
name => $tmpnam,
|
|
|
|
rio => $fields[0],
|
|
|
|
rmerge => $fields[1],
|
|
|
|
rsect => $fields[2],
|
|
|
|
ruse => $fields[3],
|
|
|
|
wio => $fields[4],
|
|
|
|
wmerge => $fields[5],
|
|
|
|
wsect => $fields[6],
|
|
|
|
wuse => $fields[7],
|
|
|
|
running => $fields[8],
|
|
|
|
use => $fields[9],
|
|
|
|
aveq => $fields[10]
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close (DETAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# vim:syntax=perl
|