Skip to content

Instantly share code, notes, and snippets.

@jashkenas
Created January 8, 2010 16:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jashkenas/272134 to your computer and use it in GitHub Desktop.
Save jashkenas/272134 to your computer and use it in GitHub Desktop.
#!/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
# Renamed occurrances of lrrd -> munin
#
# 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;
my $detailed_present = my $stat_present = 0;
if (system("grep -q '' /proc/diskstats > /dev/null 2>&1") == 0
|| system("grep -q 'rio rmerge rsect ruse wio wmerge wsect wuse running use aveq' /proc/partitions > /dev/null 2>&1") == 0)
{
$detailed_present = 1;
}
elsif (system("grep -q '^disk_io: [^ ]' /proc/stat") == 0)
{
$stat_present = 1;
}
if ( $ARGV[0] and $ARGV[0] eq "autoconf")
{
if ($detailed_present eq 1 || $stat_present eq 1)
{
print "yes\n";
exit 0;
}
print "no\n";
exit 1;
}
my %devs;
if ($detailed_present eq 1)
{
&fetch_detailed;
}
# Falling back to /proc/stat
elsif ($stat_present eq 1)
{
&fetch_stat;
}
if ( $ARGV[0] and $ARGV[0] eq "config")
{
print "graph_title IOstat\n";
print "graph_args --base 1024 -l 0\n";
print "graph_vlabel blocks per \${graph_period} read (-) / written (+)\n";
print "graph_category disk\n";
print "graph_total Total\n" if (keys (%devs) > 1);
print "graph_info This graph shows the I/O to and from block devices.\n";
print "graph_order";
foreach my $key (sort by_dev keys %devs)
{
print " ", $key, "_read ", $key, "_write ";
}
print "\n";
foreach my $key (sort by_dev keys %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";
}
exit 0;
}
foreach my $key (sort by_dev keys %devs)
{
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;
$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 =~ /\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$//;
$devs{"dev".$major."_".&get_disk_count($major)} =
{
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment