#!/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 [ "${MUNIN_CAP_DIRTYCONFIG:-}" = "1" ] && fetch ;; *) fetch ;; esac exit 0