NET-SNMP Linux disk IO collector, mark III

NET-SNMP Linux disk IO collector, mark III

Ok, this might be the last one ;-)

As mentioned previously, I’ve been writing a script that net-snmp can pass off the UCD-DISKIO-MIB requests to, for those versions that don’t have it built in, and to save one from rebuilding net-snmp packages.

This time around, I’ve added support for 2.4 series kernels, which use /proc/partitions instead of /proc/diskstats to log the disk IO stats.

I’ve now got this running in production across a handful of machines, and it’s pretty neat – I am able to see the shape of disk traffic during a vacuum on one of our machines, alongside the CPU and memory usage, and load average graphs, for example.

As before, plop it into /usr/local/sbin/snmp-diskio-collector and add this line to your snmpd.conf:

pass .1.3.6.1.4.1.2021.13.15 /usr/local/sbin/snmp-diskio-collector

Here’s the script:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/sh

# by Jamie Wilkinson <jamie@anchor.net.au>
# this code is in the public domain
# based on passtest from the net-snmp distribution examples
# WARNING there is shitloads of IO required to get this information :)

debug_flag=0

debug () {
    if [ $debug_flag -eq 1 ]; then
        echo $* >> /tmp/snmp-diskio-collector-debug.log
    fi
}

PLACE=".1.3.6.1.4.1.2021.13.15"
REQ="$2"

debug
debug "new run" 
debug "args $*" 
if [ "$1" = "-s" ]; then
  exit 0
fi

# the 'tail' of the oid, everything after $PLACE
oidtail=`echo $REQ | sed "s/^$PLACE//"`
debug "oidtail=$oidtail" 

# number of devices we can export
if [ -f /proc/diskstats ]; then
    devcount=`wc -l /proc/diskstats | sed 's/^ *//' | cut -f1 -d' '`
else
    devcount=`wc -l /proc/partitions | sed 's/^ *//' | cut -f1 -d' '`
    devcount=`expr $devcount - 2`
fi
debug "devcount=$devcount" 

item=`echo $oidtail | cut -f4 -d.`
index=`echo $oidtail | cut -f5 -d.`
debug "oidtail=$oidtail, item=$item, index=$index" 

if [ "$1" = "-n" ]; then
    if [ -z "$item" ]; then
        item=1
        index=1
    elif [ -z "$index" ]; then
        index=1
    else
        index=`expr $index + 1`
        if [ "$index" -gt "$devcount" ]; then
            index=1
            item=`expr $item + 1`
            if [ "$item" -gt 6 ]; then
                # break out of the loop
                exit 0;
            fi
        fi
    fi
    RET=$PLACE.1.1.$item.$index
else
    case "$REQ" in
        $PLACE) exit 0;;
        *) RET=$REQ ;;
    esac
fi

debug "after -n, item=$item, index=$index" 
debug "RET is now $RET" 

echo "$RET"

debug "oidtail=$oidtail, item=$item, index=$index" 

# awk uses this variable in the environment below
export index
# see linux kernel Documentation/iostats.txt for format
if [ -n "$index" ]; then
    case "$item" in
        1)
            # diskIOIndex
            debug "result: diskIOIndex $index" 
            echo "integer"
            echo $index
            exit 0
            ;;
        2)
            # diskIODevice
            debug "result: diskIODevice $index" 
            echo "string"
	    if [ -f /proc/diskstats ]; then
		awk 'FNR == ENVIRON["index"] { print $3 }' /proc/diskstats
	    else
		awk 'FNR == ENVIRON["index"] + 2 { print $4 }' /proc/partitions
	    fi
            exit 0
            ;;
        3)
            # diskIONRead
            debug "result: diskIONRead $index" 
            echo "counter"
	    if [ -f /proc/diskstats ]; then
		awk 'FNR == ENVIRON["index"] { print $6 }' /proc/diskstats
	    else
		awk 'FNR == ENVIRON["index"] + 2 { print $7 }' /proc/partitions
	    fi
            exit 0
            ;;
        4)
            # diskIONWritten
            debug "result: diskIONWritten $index" 
            echo "counter"
	    if [ -f /proc/diskstats ]; then
		awk 'FNR == ENVIRON["index"] { print $10 }' /proc/diskstats
	    else
		awk 'FNR == ENVIRON["index"] + 2 { print $11 }' /proc/partitions
	    fi
            exit 0
            ;;
        5)
            # diskIOReads
            debug "result: diskIOReads $index" 
            echo "counter"
	    if [ -f /proc/diskstats ]; then
		awk 'FNR == ENVIRON["index"] { print $4 }' /proc/diskstats
	    else
		awk 'FNR == ENVIRON["index"] + 2 { print $5 }' /proc/partitions
	    fi
            exit 0
            ;;
        6)
            # diskIOWrites
            debug "result: diskIOWrites $index" 
            echo "counter"
	    if [ -f /proc/diskstats ]; then
		awk 'FNR == ENVIRON["index"] { print $8 }' /proc/diskstats
	    else
		awk 'FNR == ENVIRON["index"] + 2 { print $9 }' /proc/partitions
	    fi
            exit 0
            ;;
        *) exit 0; #echo "string"; echo "debug... $RET $REQ"; exit 0 ;;
    esac
else
    exit 0
fi