2017-03-24 15:14:47 +01:00
|
|
|
#!/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
|
2017-03-27 09:23:33 +02:00
|
|
|
busy : similar to iostat %b, %w (%w usually indicates 0 in Sol10,11)
|
2017-03-24 15:14:47 +01:00
|
|
|
queue : similar to iostat actv, wait
|
|
|
|
latency : similar to iostat asvc_t, wsvc_t
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
This plugin is improved from Solaris io_busy_, io_ops_, io_bytes_ plugins.
|
2017-03-24 15:14:47 +01:00
|
|
|
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.
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
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)
|
|
|
|
|
2017-03-24 15:14:47 +01:00
|
|
|
=head1 ENVIRONMENT VARIABLES
|
|
|
|
|
|
|
|
env.class - kstat class. See man kstat -c option.
|
|
|
|
example: env.class /disk|nfs|tape/
|
|
|
|
default: disk
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
env.module - Module name. Only used in internal graph name.
|
2017-03-24 15:14:47 +01:00
|
|
|
example: env.module something
|
|
|
|
default: sd
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
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.
|
|
|
|
|
2017-03-24 15:14:47 +01:00
|
|
|
env.module_regex - kstat module. See man kstat -m option.
|
|
|
|
example: env.module_regex /^(s?sd|vdc|zvblk|dad|md|nfs|tape)$/
|
|
|
|
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
|
|
|
|
set -o pipefail
|
|
|
|
|
|
|
|
# Set environment variables
|
|
|
|
plugin_name=io
|
|
|
|
functions='ops bytes busy queue latency'
|
|
|
|
: "${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)
|
|
|
|
# ...
|
|
|
|
declare $( paste -d= \
|
|
|
|
<( iostat -x | awk '{print $1}' | sed -e '1,2d' -e 's/^/name_/' ) \
|
|
|
|
<( iostat -xn | awk '{print $NF}' | sed -e '1,2d' -e 's/^\(c[0-9]*\)\(t.\{2\}\).*\(.\{4\}\)\(d[0-9]*\)$/\1\2_\3\4/' ) \
|
|
|
|
)
|
|
|
|
|
|
|
|
# Functions
|
|
|
|
|
|
|
|
preconfig() {
|
|
|
|
local func
|
|
|
|
func=$1
|
|
|
|
|
|
|
|
case "$func" in
|
|
|
|
ops)
|
|
|
|
conf_title='I/O Operations'
|
|
|
|
conf_in=reads
|
|
|
|
conf_out=writes
|
|
|
|
conf_cdef=
|
|
|
|
conf_gargs='--base 1000'
|
|
|
|
conf_vlabel='Ops per second write (-) / read (+)'
|
|
|
|
;;
|
|
|
|
bytes)
|
|
|
|
conf_title='I/O Throughput'
|
|
|
|
conf_in=nread
|
|
|
|
conf_out=nwritten
|
|
|
|
conf_cdef=
|
|
|
|
conf_gargs='--base 1024'
|
|
|
|
conf_vlabel='Bytes per second write (-) / read (+)'
|
|
|
|
;;
|
|
|
|
busy)
|
|
|
|
conf_title='Busy & Wait'
|
|
|
|
conf_in=rtime
|
|
|
|
conf_out=wtime
|
|
|
|
conf_cdef=',100,*'
|
|
|
|
conf_gargs='--base 1000 --lower-limit 0 --upper-limit 100'
|
|
|
|
conf_vlabel='% wait (-) / busy (+)'
|
|
|
|
;;
|
|
|
|
queue)
|
|
|
|
conf_title='Queue Length'
|
|
|
|
conf_in=rlentime
|
|
|
|
conf_out=wlentime
|
|
|
|
conf_cdef=
|
|
|
|
conf_gargs='--base 1000'
|
|
|
|
conf_vlabel='Queue length wait (-) / actv (+)'
|
|
|
|
;;
|
|
|
|
latency)
|
|
|
|
conf_title='Latency'
|
|
|
|
conf_in=rlentime
|
|
|
|
conf_out=wlentime
|
|
|
|
conf_cdef=
|
|
|
|
conf_gargs='--base 1000'
|
|
|
|
conf_vlabel='Seconds wsvc_t (-) / asvc_t (+)'
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo "Unknown function: $func"
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
is_excluded() {
|
|
|
|
local dev i
|
|
|
|
dev=$1
|
|
|
|
|
|
|
|
for i in ${exclude}
|
|
|
|
do
|
|
|
|
if [ "$dev" = "$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
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
# Get device instance names by kstat
|
2017-03-24 15:14:47 +01:00
|
|
|
kstat -p -c "$class" -m "$module_regex" -s "/^${conf_in}\$/" | sed 's/:/ /g' | awk '{ print $3 }' | \
|
|
|
|
while read -r dev
|
|
|
|
do
|
2017-03-27 09:23:33 +02:00
|
|
|
is_excluded "$dev" && continue
|
2017-03-24 15:14:47 +01:00
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
# Replace instance name to logical device name if exists
|
2017-03-24 15:14:47 +01:00
|
|
|
ref="name_$dev"
|
2017-03-27 09:23:33 +02:00
|
|
|
devname=${!ref:-} # ${!varname} means indirect evaluation (similar to eval)
|
2017-03-24 15:14:47 +01:00
|
|
|
|
|
|
|
# reads and writes are necessary to calculate latency
|
|
|
|
if [ "$func" = 'latency' ]; then
|
|
|
|
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
|
|
|
|
# rlentime / ( reads + writes )
|
|
|
|
conf_cdef=,${dev}_reads,${dev}_writes,+,/
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "${dev}_${conf_out}.label dummy"
|
|
|
|
echo "${dev}_${conf_out}.graph no"
|
|
|
|
echo "${dev}_${conf_out}.type DERIVE"
|
|
|
|
echo "${dev}_${conf_out}.min 0"
|
|
|
|
|
|
|
|
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_cdef" ]; then
|
|
|
|
echo "${dev}_${conf_out}.cdef ${dev}_${conf_out}${conf_cdef}"
|
|
|
|
echo "${dev}_${conf_in}.cdef ${dev}_${conf_in}${conf_cdef}"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
echo
|
|
|
|
}
|
|
|
|
|
|
|
|
do_getvalue() {
|
|
|
|
local func stat_regex dev stat value
|
|
|
|
|
|
|
|
func=$1
|
|
|
|
preconfig "$func"
|
|
|
|
|
|
|
|
if [ "$func" = 'latency' ]; then
|
|
|
|
stat_regex="/^($conf_in|$conf_out|reads|writes)\$/"
|
|
|
|
else
|
|
|
|
stat_regex="/^($conf_in|$conf_out)\$/"
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "multigraph ${plugin_name}_${func}_${module}"
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
# 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
|
|
|
|
# ...
|
|
|
|
|
2017-03-24 15:14:47 +01:00
|
|
|
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
|
2017-03-27 09:23:33 +02:00
|
|
|
is_excluded "$dev" && continue
|
2017-03-24 15:14:47 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
getvalue() {
|
|
|
|
local func
|
|
|
|
|
|
|
|
for func in $functions
|
|
|
|
do
|
|
|
|
do_getvalue "$func"
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2017-03-27 09:23:33 +02:00
|
|
|
# Main
|
2017-03-24 15:14:47 +01:00
|
|
|
case ${1:-} in
|
|
|
|
autoconf)
|
|
|
|
autoconf
|
|
|
|
;;
|
|
|
|
config)
|
|
|
|
config
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
getvalue
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
exit 0
|