diff --git a/plugins/solaris/io_disk b/plugins/solaris/io_disk new file mode 100755 index 00000000..ee2c11d8 --- /dev/null +++ b/plugins/solaris/io_disk @@ -0,0 +1,301 @@ +#!/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 + queue : similar to iostat actv, wait + latency : similar to iostat asvc_t, wsvc_t + + 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. + +=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. If you would not + to like to take over RRDs generated by io_*_sd plugins, please change it + to another name. + + example: env.module something + default: sd + + 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 + + kstat -p -c "$class" -m "$module_regex" -s "/^${conf_in}\$/" | sed 's/:/ /g' | awk '{ print $3 }' | \ + while read -r dev + do + if is_excluded "$dev" ; then + continue + fi + + # replace instance name to logical device name if exists + ref="name_$dev" + devname=${!ref:-} + + # 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}" + + 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 + if is_excluded "$dev" ; then + continue + fi + + 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 +} + +# main +case ${1:-} in +autoconf) + autoconf + ;; +config) + config + ;; +*) + getvalue + ;; +esac + +exit 0