munin-contrib/plugins/solaris/io_disk

345 lines
8.6 KiB
Bash
Executable File

#!/bin/bash
: << =cut
=head1 NAME
io_disk - Multigraph plugin to monitor disks for Solaris.
These functions are implemented:
ops : similar to iostat r/s, w/s
bytes : similar to iostat kr/s, kw/s
busy : similar to iostat %b, %w (%w usually indicates 0 in Sol10,11)
queue : similar to iostat actv, wait
latency : similar to iostat asvc_t, wsvc_t
size : average io size
This plugin is improved from Solaris io_busy_, io_ops_, io_bytes_ plugins.
Any device found in /usr/bin/kstat can be monitored.
Tested with Solaris 10 and 11, and it should work with Solaris 8, 9.
=head1 CONFIGURATION
Make symlink:
cd /path/to/munin/etc/plugins
ln -s /path/to/munin/lib/plugins/io_disk .
The RRD files generated by io_busy_, io_ops_, io_bytes_ can be taken over
by this plugin.
Thus, please remove symlinks of those plugins before using this plugin.
By default, this plugin monitors disk devices. And also it can monitor
NFS and Tape devices as much as io_* plugins with setting environments.
Note that instance names of nfs (e.g. nfs1) can be changed after reboot or
remount, this plugin may not monitor nfs properly. (same as original ones)
=head1 ENVIRONMENT VARIABLES
env.class - kstat class. See man kstat -c option.
example: env.class /disk|nfs|tape/
default: disk
env.module - Module name. Only used in internal graph name.
example: env.module something
default: sd
If you would not like to take over RRDs generated by io_*_sd plugins,
please change it to another name.
And also, if you would like to take over RRDs of nfs, tape devices,
please set it 'nfs' or 'tape' (and set env.class, env.module_regex).
It may be good to link like ln -s /path/to/io_disk io_nfs if necessary.
env.module_regex - kstat module. See man kstat -m option.
example: env.module_regex /^(s?sd|vdc|zvblk|dad|md|nfs|st)$/
default: /^(s?sd|vdc|zvblk|dad|md)$/
env.title_type - Device type shown in graph title.
example: env.title_type Disk Device, NFS, Tape
default: Disk Device
env.exclude - Device instance name(s) to exclude seperated by white-space.
example: env.exclude sd0 ssd1
default: none
env.graph_width - Graph width in pixel
example: env.graph_width 450
default: none (usually 400)
=head1 AUTHOR
Unknown Author
Improved by K.Cima https://github.com/shakemid
=head1 LICENSE
GPLv2
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=cut
# Include plugin.sh
. "${MUNIN_LIBDIR:-}/plugins/plugin.sh"
is_multigraph "$@"
# Shell options
set -o nounset # Like perl use strict;
# Set environment variables
plugin_name=io
functions='ops bytes busy queue latency size'
: "${class:=disk}"
: "${module:=sd}"
: "${module_regex:=/^(s?sd|vdc|zvblk|dad|md)\$/}"
: "${title_type:=Disk Device}"
: "${exclude:=}"
: "${graph_width:=}"
# Create map of instance name (e.g. sd0) and logical device name (e.g. c0t0d0)
# Example:
# name_sd1=c0t0d0
# name_ssd2=c0tAB_1234d0 (shorten long target)
# ...
instance_names=$( iostat -x | sed -e '1,2d' | awk '{print $1}' \
| sed -e 's/^/name_/' )
logical_device_names=$( iostat -xn | sed -e '1,2d' | awk '{print $NF}' \
| sed -e 's/^\(c[0-9]*\)\(t.\{2\}\).*\(.\{4\}\)\(d[0-9]*\)$/\1\2_\3\4/' )
declare $( paste -d= <( echo "$instance_names" ) <( echo "$logical_device_names" ) )
# Functions
preconfig() {
local func
func=$1
case "$func" in
ops)
conf_title='I/O Operations'
conf_gargs='--base 1000'
conf_vlabel='Ops per second write (-) / read (+)'
conf_in=reads
conf_out=writes
;;
bytes)
conf_title='I/O Throughput'
conf_gargs='--base 1024'
conf_vlabel='Bytes per second write (-) / read (+)'
conf_in=nread
conf_out=nwritten
;;
busy)
conf_title='Busy & Wait'
conf_gargs='--base 1000 --lower-limit 0 --upper-limit 100'
conf_vlabel='% wait (-) / busy (+)'
conf_in=rtime
conf_out=wtime
;;
queue)
conf_title='Queue Length'
conf_gargs='--base 1000'
conf_vlabel='Queue length wait (-) / actv (+)'
conf_in=rlentime
conf_out=wlentime
;;
latency)
conf_title='Latency'
conf_gargs='--base 1000'
conf_vlabel='Seconds wsvc_t (-) / asvc_t (+)'
conf_in=rlentime
conf_out=wlentime
;;
size)
conf_title='I/O Size'
conf_gargs='--base 1024'
conf_vlabel='Average size write (-) / read (+)'
conf_in=nread
conf_out=nwritten
;;
*)
echo "Unknown function: $func"
exit 1
;;
esac
}
is_excluded() {
local arg i
arg=$1
for i in ${exclude}
do
if [ "$arg" = "$i" ]; then
return 0
fi
done
return 1
}
do_config() {
local func dev ref devname stat
func=$1
preconfig "$func"
echo "multigraph ${plugin_name}_${func}_${module}"
echo "graph_title $title_type $conf_title"
echo 'graph_category disk'
echo "graph_args $conf_gargs"
echo "graph_vlabel $conf_vlabel"
if [ -n "$graph_width" ]; then
echo "graph_width $graph_width"
fi
# Get device instance names by kstat
kstat -p -c "$class" -m "$module_regex" -s "/^${conf_in}\$/" \
| sed 's/:/ /g' | awk '{ print $3 }' \
| while read -r dev
do
is_excluded "$dev" && continue
# Replace instance name to logical device name if exists
ref="name_$dev"
devname=${!ref:-} # ${!varname} means indirect evaluation (similar to eval)
# reads and writes are necessary to calculate latency, size
case "$func" in
latency|size)
for stat in reads writes
do
echo "${dev}_${stat}.label dummy"
echo "${dev}_${stat}.graph no"
echo "${dev}_${stat}.type DERIVE"
echo "${dev}_${stat}.min 0"
done
;;
esac
# Set CDEF
case "$func" in
busy)
conf_in_cdef="${dev}_${conf_in},100,*"
conf_out_cdef="${dev}_${conf_out},100,*"
;;
latency)
# rlentime / ( reads + writes )
conf_in_cdef="${dev}_${conf_in},${dev}_reads,${dev}_writes,+,/"
conf_out_cdef="${dev}_${conf_out},${dev}_reads,${dev}_writes,+,/"
;;
size)
conf_in_cdef="${dev}_${conf_in},${dev}_reads,/"
conf_out_cdef="${dev}_${conf_out},${dev}_writes,/"
;;
*)
conf_in_cdef=
conf_out_cdef=
;;
esac
# Print data attributes
echo "${dev}_${conf_out}.label dummy"
echo "${dev}_${conf_out}.graph no"
echo "${dev}_${conf_out}.type DERIVE"
echo "${dev}_${conf_out}.min 0"
if [ -n "$conf_out_cdef" ]; then
echo "${dev}_${conf_out}.cdef ${conf_out_cdef}"
fi
echo "${dev}_${conf_in}.label ${devname:-${dev}}"
echo "${dev}_${conf_in}.negative ${dev}_${conf_out}"
echo "${dev}_${conf_in}.type DERIVE"
echo "${dev}_${conf_in}.min 0"
if [ -n "$conf_in_cdef" ]; then
echo "${dev}_${conf_in}.cdef ${conf_in_cdef}"
fi
done
echo
}
do_fetch() {
local func stat_regex dev stat value
func=$1
preconfig "$func"
echo "multigraph ${plugin_name}_${func}_${module}"
case "$func" in
latency|size)
stat_regex="/^($conf_in|$conf_out|reads|writes)\$/"
;;
*)
stat_regex="/^($conf_in|$conf_out)\$/"
;;
esac
# Get device instance names, stat names and values by kstat
# kstat output example:
# $ kstat -p -c disk -m '/^sd$/' -s '/^reads$/'
# sd:0:sd0:reads 51432610
# sd:1:sd1:reads 52671435
# ...
kstat -p -c "$class" -m "$module_regex" -s "$stat_regex" \
| sed 's/:/ /g' | awk '{ print $3,$4,$5 }' \
| while read -r dev stat value
do
is_excluded "$dev" && continue
echo "${dev}_${stat}.value ${value%.*}"
done
echo
}
autoconf() {
if [ -x /usr/bin/kstat ]; then
echo yes
exit 0
else
echo "no (/usr/bin/kstat not found)"
exit 0
fi
}
config() {
local func
for func in $functions
do
do_config "$func"
done
}
fetch() {
local func
for func in $functions
do
do_fetch "$func"
done
}
# Main
case ${1:-} in
autoconf)
autoconf
;;
config)
config
if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = "1" ]; then fetch; fi
;;
*)
fetch
;;
esac
exit 0