Home | History | Annotate | Line # | Download | only in contrib
      1      1.1  christos #!/bin/sh
      2      1.1  christos #
      3      1.1  christos # plugin for munin to monitor usage of unbound servers.
      4      1.1  christos # To install copy this to /usr/local/share/munin/plugins/unbound_munin_
      5      1.1  christos # and use munin-node-configure (--suggest, --shell).
      6      1.1  christos #
      7      1.1  christos # (C) 2008 W.C.A. Wijngaards.  BSD Licensed.
      8      1.1  christos #
      9      1.1  christos # To install; enable statistics and unbound-control in unbound.conf
     10      1.1  christos #	server:		extended-statistics: yes
     11      1.1  christos #			statistics-cumulative: no
     12      1.1  christos #			statistics-interval: 0
     13      1.1  christos #	remote-control:	control-enable: yes
     14      1.1  christos # Run the command unbound-control-setup to generate the key files.
     15      1.1  christos #
     16      1.1  christos # Environment variables for this script
     17      1.1  christos #	unbound_conf	- where the unbound.conf file is located.
     18      1.1  christos #	unbound_control	- where to find unbound-control executable.
     19      1.1  christos #	spoof_warn	- what level to warn about spoofing
     20      1.1  christos #	spoof_crit	- what level to crit about spoofing
     21      1.1  christos #
     22      1.1  christos # You can set them in your munin/plugin-conf.d/plugins.conf file
     23      1.1  christos # with:
     24      1.1  christos # [unbound*]
     25      1.1  christos # user root
     26      1.1  christos # env.unbound_conf /usr/local/etc/unbound/unbound.conf
     27      1.1  christos # env.unbound_control /usr/local/sbin/unbound-control
     28      1.1  christos # env.spoof_warn 1000
     29      1.1  christos # env.spoof_crit 100000
     30      1.1  christos #
     31      1.1  christos # This plugin can create different graphs depending on what name
     32      1.1  christos # you link it as (with ln -s) into the plugins directory
     33      1.1  christos # You can link it multiple times.
     34      1.1  christos # If you are only a casual user, the _hits and _by_type are most interesting,
     35      1.1  christos # possibly followed by _by_rcode.
     36      1.1  christos #
     37      1.1  christos #	unbound_munin_hits	- base volume, cache hits, unwanted traffic
     38      1.1  christos #	unbound_munin_queue	- to monitor the internal requestlist
     39      1.1  christos #	unbound_munin_memory	- memory usage
     40      1.1  christos #	unbound_munin_by_type	- incoming queries by type
     41      1.1  christos #	unbound_munin_by_class	- incoming queries by class
     42      1.1  christos #	unbound_munin_by_opcode	- incoming queries by opcode
     43      1.1  christos #	unbound_munin_by_rcode	- answers by rcode, validation status
     44      1.1  christos #	unbound_munin_by_flags	- incoming queries by flags
     45      1.1  christos #	unbound_munin_histogram	- histogram of query resolving times
     46      1.1  christos #
     47      1.1  christos # Magic markers - optional - used by installation scripts and
     48      1.1  christos # munin-config:  (originally contrib family but munin-node-configure ignores it)
     49      1.1  christos #
     50      1.1  christos #%# family=auto
     51      1.1  christos #%# capabilities=autoconf suggest
     52      1.1  christos 
     53      1.1  christos # POD documentation
     54      1.1  christos : <<=cut
     55      1.1  christos =head1 NAME
     56      1.1  christos 
     57      1.1  christos unbound_munin_ - Munin plugin to monitor the Unbound DNS resolver.
     58      1.1  christos 
     59      1.1  christos =head1 APPLICABLE SYSTEMS
     60      1.1  christos 
     61      1.1  christos System with unbound daemon.
     62      1.1  christos 
     63      1.1  christos =head1 CONFIGURATION
     64      1.1  christos 
     65      1.1  christos   [unbound*]
     66      1.1  christos   user root
     67      1.1  christos   env.unbound_conf /usr/local/etc/unbound/unbound.conf
     68      1.1  christos   env.unbound_control /usr/local/sbin/unbound-control
     69      1.1  christos   env.spoof_warn 1000
     70      1.1  christos   env.spoof_crit 100000
     71      1.1  christos 
     72      1.1  christos Use the .env settings to override the defaults.
     73      1.1  christos 
     74      1.1  christos =head1 USAGE
     75      1.1  christos 
     76      1.1  christos Can be used to present different graphs. Use ln -s for that name in
     77      1.1  christos the plugins directory to enable the graph.
     78      1.1  christos unbound_munin_hits	- base volume, cache hits, unwanted traffic
     79      1.1  christos unbound_munin_queue	- to monitor the internal requestlist
     80      1.1  christos unbound_munin_memory	- memory usage
     81      1.1  christos unbound_munin_by_type	- incoming queries by type
     82      1.1  christos unbound_munin_by_class	- incoming queries by class
     83      1.1  christos unbound_munin_by_opcode	- incoming queries by opcode
     84      1.1  christos unbound_munin_by_rcode	- answers by rcode, validation status
     85      1.1  christos unbound_munin_by_flags	- incoming queries by flags
     86      1.1  christos unbound_munin_histogram - histogram of query resolving times
     87      1.1  christos 
     88      1.1  christos =head1 AUTHOR
     89      1.1  christos 
     90      1.1  christos Copyright 2008 W.C.A. Wijngaards
     91      1.1  christos 
     92      1.1  christos =head1 LICENSE
     93      1.1  christos 
     94      1.1  christos BSD
     95      1.1  christos 
     96      1.1  christos =cut
     97      1.1  christos 
     98  1.1.1.4  christos state="${MUNIN_PLUGSTATE}/unbound.state"
     99  1.1.1.4  christos seentags="${MUNIN_PLUGSTATE}/unbound-seentags.state"
    100      1.1  christos conf=${unbound_conf:-/usr/local/etc/unbound/unbound.conf}
    101      1.1  christos ctrl=${unbound_control:-/usr/local/sbin/unbound-control}
    102      1.1  christos warn=${spoof_warn:-1000}
    103      1.1  christos crit=${spoof_crit:-100000}
    104      1.1  christos lock=$state.lock
    105      1.1  christos 
    106      1.1  christos # number of seconds between polling attempts.
    107      1.1  christos # makes the statefile hang around for at least this many seconds,
    108      1.1  christos # so that multiple links of this script can share the results.
    109      1.1  christos lee=55
    110      1.1  christos 
    111      1.1  christos # to keep things within 19 characters
    112      1.1  christos ABBREV="-e s/total/t/ -e s/thread/t/ -e s/num/n/ -e s/query/q/ -e s/answer/a/ -e s/unwanted/u/ -e s/requestlist/ql/ -e s/type/t/ -e s/class/c/ -e s/opcode/o/ -e s/rcode/r/ -e s/edns/e/ -e s/mem/m/ -e s/cache/c/ -e s/mod/m/"
    113      1.1  christos 
    114      1.1  christos # get value from $1 into return variable $value
    115      1.1  christos get_value ( ) {
    116      1.1  christos 	value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`"
    117      1.1  christos 	if test "$value"x = ""x; then
    118      1.1  christos 		value="0"
    119      1.1  christos 	fi
    120      1.1  christos }
    121      1.1  christos 
    122  1.1.1.4  christos # Update list of seen query types etc to seentags file. This is run while
    123  1.1.1.4  christos # holding the lock, after the state file is updated.
    124  1.1.1.4  christos update_seentags() {
    125  1.1.1.4  christos     tmplist="$(cat ${seentags} 2> /dev/null)
    126  1.1.1.4  christos num.query.type.A
    127  1.1.1.4  christos num.query.class.IN
    128  1.1.1.4  christos num.query.opcode.QUERY
    129  1.1.1.4  christos num.answer.rcode.NOERROR
    130  1.1.1.4  christos "
    131  1.1.1.4  christos     (echo "${tmplist}"; grep ^num ${state} | sed -e 's/=.*//') | sort -u > ${seentags}
    132  1.1.1.4  christos }
    133  1.1.1.4  christos 
    134      1.1  christos # download the state from the unbound server.
    135      1.1  christos get_state ( ) {
    136      1.1  christos 	# obtain lock for fetching the state
    137      1.1  christos 	# because there is a race condition in fetching and writing to file
    138      1.1  christos 
    139  1.1.1.4  christos 	# see if the lock is stale, if so, take it
    140      1.1  christos 	if test -f $lock ; then
    141      1.1  christos 		pid="`cat $lock 2>&1`"
    142      1.1  christos 		kill -0 "$pid" >/dev/null 2>&1
    143      1.1  christos 		if test $? -ne 0 -a "$pid" != $$ ; then
    144      1.1  christos 			echo $$ >$lock
    145      1.1  christos 		fi
    146      1.1  christos 	fi
    147      1.1  christos 
    148      1.1  christos 	i=0
    149      1.1  christos 	while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do
    150      1.1  christos 		while test -f $lock; do
    151      1.1  christos 			# wait
    152      1.1  christos 			i=`expr $i + 1`
    153      1.1  christos 			if test $i -gt 1000; then
    154      1.1  christos 				sleep 1;
    155      1.1  christos 			fi
    156      1.1  christos 			if test $i -gt 1500; then
    157      1.1  christos 				echo "error locking $lock" "=" `cat $lock`
    158      1.1  christos 				rm -f $lock
    159      1.1  christos 				exit 1
    160      1.1  christos 			fi
    161      1.1  christos 		done
    162      1.1  christos 		# try to get it
    163  1.1.1.2  christos 		if echo $$ >$lock ; then : ; else break; fi
    164      1.1  christos 	done
    165      1.1  christos 	# do not refetch if the file exists and only LEE seconds old
    166      1.1  christos 	if test -f $state; then
    167      1.1  christos 		now=`date +%s`
    168      1.1  christos 		get_value "time.now"
    169      1.1  christos 		value="`echo $value | sed -e 's/\..*$//'`"
    170      1.1  christos 		if test $now -lt `expr $value + $lee`; then
    171      1.1  christos 			rm -f $lock
    172      1.1  christos 			return
    173      1.1  christos 		fi
    174      1.1  christos 	fi
    175      1.1  christos 	$ctrl -c $conf stats > $state
    176      1.1  christos 	if test $? -ne 0; then
    177      1.1  christos 		echo "error retrieving data from unbound server"
    178      1.1  christos 		rm -f $lock
    179      1.1  christos 		exit 1
    180      1.1  christos 	fi
    181  1.1.1.4  christos 	update_seentags
    182      1.1  christos 	rm -f $lock
    183      1.1  christos }
    184      1.1  christos 
    185      1.1  christos if test "$1" = "autoconf" ; then
    186      1.1  christos 	if test ! -f $conf; then
    187      1.1  christos 		echo no "($conf does not exist)"
    188  1.1.1.3  christos 		exit 0
    189      1.1  christos 	fi
    190      1.1  christos 	if test ! -d `dirname $state`; then
    191      1.1  christos 		echo no "(`dirname $state` directory does not exist)"
    192  1.1.1.3  christos 		exit 0
    193      1.1  christos 	fi
    194      1.1  christos 	echo yes
    195      1.1  christos 	exit 0
    196      1.1  christos fi
    197      1.1  christos 
    198      1.1  christos if test "$1" = "suggest" ; then
    199      1.1  christos 	echo "hits"
    200      1.1  christos 	echo "queue"
    201      1.1  christos 	echo "memory"
    202      1.1  christos 	echo "by_type"
    203      1.1  christos 	echo "by_class"
    204      1.1  christos 	echo "by_opcode"
    205      1.1  christos 	echo "by_rcode"
    206      1.1  christos 	echo "by_flags"
    207      1.1  christos 	echo "histogram"
    208      1.1  christos 	exit 0
    209      1.1  christos fi
    210      1.1  christos 
    211      1.1  christos # determine my type, by name
    212      1.1  christos id=`echo $0 | sed -e 's/^.*unbound_munin_//'`
    213      1.1  christos if test "$id"x = ""x; then
    214      1.1  christos 	# some default to keep people sane.
    215      1.1  christos 	id="hits"
    216      1.1  christos fi
    217      1.1  christos 
    218      1.1  christos # if $1 exists in statefile, config is echoed with label $2
    219      1.1  christos exist_config ( ) {
    220      1.1  christos 	mn=`echo $1 | sed $ABBREV | tr . _`
    221      1.1  christos 	if grep '^'$1'=' $state >/dev/null 2>&1; then
    222      1.1  christos 		echo "$mn.label $2"
    223      1.1  christos 		echo "$mn.min 0"
    224      1.1  christos 		echo "$mn.type ABSOLUTE"
    225      1.1  christos 	fi
    226      1.1  christos }
    227      1.1  christos 
    228      1.1  christos # print label and min 0 for a name $1 in unbound format
    229      1.1  christos p_config ( ) {
    230      1.1  christos 	mn=`echo $1 | sed $ABBREV | tr . _`
    231      1.1  christos 	echo $mn.label "$2"
    232      1.1  christos 	echo $mn.min 0
    233      1.1  christos 	echo $mn.type $3
    234      1.1  christos }
    235      1.1  christos 
    236      1.1  christos if test "$1" = "config" ; then
    237      1.1  christos 	if test ! -f $state; then
    238      1.1  christos 		get_state
    239      1.1  christos 	fi
    240      1.1  christos 	case $id in
    241      1.1  christos 	hits)
    242      1.1  christos 		echo "graph_title Unbound DNS traffic and cache hits"
    243      1.1  christos 		echo "graph_args --base 1000 -l 0"
    244      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    245      1.1  christos 		echo "graph_scale no"
    246  1.1.1.4  christos 		echo "graph_category dns"
    247      1.1  christos 		for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state |
    248      1.1  christos 			sed -e 's/=.*//'`; do
    249      1.1  christos 			exist_config $x "queries handled by `basename $x .num.queries`"
    250      1.1  christos 		done
    251      1.1  christos 		p_config "total.num.queries" "total queries from clients" "ABSOLUTE"
    252      1.1  christos 		p_config "total.num.cachehits" "cache hits" "ABSOLUTE"
    253      1.1  christos 		p_config "total.num.prefetch" "cache prefetch" "ABSOLUTE"
    254      1.1  christos 		p_config "num.query.tcp" "TCP queries" "ABSOLUTE"
    255      1.1  christos 		p_config "num.query.tcpout" "TCP out queries" "ABSOLUTE"
    256  1.1.1.4  christos 		p_config "num.query.udpout" "UDP out queries" "ABSOLUTE"
    257  1.1.1.3  christos 		p_config "num.query.tls" "TLS queries" "ABSOLUTE"
    258  1.1.1.3  christos 		p_config "num.query.tls.resume" "TLS resumes" "ABSOLUTE"
    259      1.1  christos 		p_config "num.query.ipv6" "IPv6 queries" "ABSOLUTE"
    260      1.1  christos 		p_config "unwanted.queries" "queries that failed acl" "ABSOLUTE"
    261      1.1  christos 		p_config "unwanted.replies" "unwanted or unsolicited replies" "ABSOLUTE"
    262      1.1  christos 		echo "u_replies.warning $warn"
    263      1.1  christos 		echo "u_replies.critical $crit"
    264      1.1  christos 		echo "graph_info DNS queries to the recursive resolver. The unwanted replies could be innocent duplicate packets, late replies, or spoof threats."
    265      1.1  christos 		;;
    266      1.1  christos 	queue)
    267      1.1  christos 		echo "graph_title Unbound requestlist size"
    268      1.1  christos 		echo "graph_args --base 1000 -l 0"
    269      1.1  christos 		echo "graph_vlabel number of queries"
    270      1.1  christos 		echo "graph_scale no"
    271  1.1.1.4  christos 		echo "graph_category dns"
    272      1.1  christos 		p_config "total.requestlist.avg" "Average size of queue on insert" "GAUGE"
    273      1.1  christos 		p_config "total.requestlist.max" "Max size of queue (in 5 min)" "GAUGE"
    274      1.1  christos 		p_config "total.requestlist.overwritten" "Number of queries replaced by new ones" "GAUGE"
    275      1.1  christos 		p_config "total.requestlist.exceeded" "Number of queries dropped due to lack of space" "GAUGE"
    276      1.1  christos 		echo "graph_info The queries that did not hit the cache and need recursion service take up space in the requestlist. If there are too many queries, first queries get overwritten, and at last resort dropped."
    277      1.1  christos 		;;
    278      1.1  christos 	memory)
    279      1.1  christos 		echo "graph_title Unbound memory usage"
    280      1.1  christos 		echo "graph_args --base 1024 -l 0"
    281      1.1  christos 		echo "graph_vlabel memory used in bytes"
    282  1.1.1.4  christos 		echo "graph_category dns"
    283      1.1  christos 		p_config "mem.cache.rrset" "RRset cache memory" "GAUGE"
    284      1.1  christos 		p_config "mem.cache.message" "Message cache memory" "GAUGE"
    285      1.1  christos 		p_config "mem.mod.iterator" "Iterator module memory" "GAUGE"
    286      1.1  christos 		p_config "mem.mod.validator" "Validator module and key cache memory" "GAUGE"
    287      1.1  christos 		p_config "msg.cache.count" "msg cache count" "GAUGE"
    288      1.1  christos 		p_config "rrset.cache.count" "rrset cache count" "GAUGE"
    289      1.1  christos 		p_config "infra.cache.count" "infra cache count" "GAUGE"
    290      1.1  christos 		p_config "key.cache.count" "key cache count" "GAUGE"
    291      1.1  christos 		echo "graph_info The memory used by unbound."
    292      1.1  christos 		;;
    293      1.1  christos 	by_type)
    294      1.1  christos 		echo "graph_title Unbound DNS queries by type"
    295      1.1  christos 		echo "graph_args --base 1000 -l 0"
    296      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    297      1.1  christos 		echo "graph_scale no"
    298  1.1.1.4  christos 		echo "graph_category dns"
    299  1.1.1.4  christos 		for nm in `grep "^num.query.type" $seentags`; do
    300      1.1  christos 			tp=`echo $nm | sed -e s/num.query.type.//`
    301      1.1  christos 			p_config "$nm" "$tp" "ABSOLUTE"
    302      1.1  christos 		done
    303      1.1  christos 		echo "graph_info queries by DNS RR type queried for"
    304      1.1  christos 		;;
    305      1.1  christos 	by_class)
    306      1.1  christos 		echo "graph_title Unbound DNS queries by class"
    307      1.1  christos 		echo "graph_args --base 1000 -l 0"
    308      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    309      1.1  christos 		echo "graph_scale no"
    310  1.1.1.4  christos 		echo "graph_category dns"
    311  1.1.1.4  christos 		for nm in `grep "^num.query.class" $seentags`; do
    312      1.1  christos 			tp=`echo $nm | sed -e s/num.query.class.//`
    313      1.1  christos 			p_config "$nm" "$tp" "ABSOLUTE"
    314      1.1  christos 		done
    315      1.1  christos 		echo "graph_info queries by DNS RR class queried for."
    316      1.1  christos 		;;
    317      1.1  christos 	by_opcode)
    318      1.1  christos 		echo "graph_title Unbound DNS queries by opcode"
    319      1.1  christos 		echo "graph_args --base 1000 -l 0"
    320      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    321      1.1  christos 		echo "graph_scale no"
    322  1.1.1.4  christos 		echo "graph_category dns"
    323  1.1.1.4  christos 		for nm in `grep "^num.query.opcode" $seentags`; do
    324      1.1  christos 			tp=`echo $nm | sed -e s/num.query.opcode.//`
    325      1.1  christos 			p_config "$nm" "$tp" "ABSOLUTE"
    326      1.1  christos 		done
    327      1.1  christos 		echo "graph_info queries by opcode in the query packet."
    328      1.1  christos 		;;
    329      1.1  christos 	by_rcode)
    330      1.1  christos 		echo "graph_title Unbound DNS answers by return code"
    331      1.1  christos 		echo "graph_args --base 1000 -l 0"
    332      1.1  christos 		echo "graph_vlabel answer packets / \${graph_period}"
    333      1.1  christos 		echo "graph_scale no"
    334  1.1.1.4  christos 		echo "graph_category dns"
    335  1.1.1.4  christos 		for nm in `grep "^num.answer.rcode" $seentags`; do
    336      1.1  christos 			tp=`echo $nm | sed -e s/num.answer.rcode.//`
    337      1.1  christos 			p_config "$nm" "$tp" "ABSOLUTE"
    338      1.1  christos 		done
    339      1.1  christos 		p_config "num.answer.secure" "answer secure" "ABSOLUTE"
    340      1.1  christos 		p_config "num.answer.bogus" "answer bogus" "ABSOLUTE"
    341      1.1  christos 		p_config "num.rrset.bogus" "num rrsets marked bogus" "ABSOLUTE"
    342      1.1  christos 		echo "graph_info answers sorted by return value. rrsets bogus is the number of rrsets marked bogus per \${graph_period} by the validator"
    343      1.1  christos 		;;
    344      1.1  christos 	by_flags)
    345      1.1  christos 		echo "graph_title Unbound DNS incoming queries by flags"
    346      1.1  christos 		echo "graph_args --base 1000 -l 0"
    347      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    348      1.1  christos 		echo "graph_scale no"
    349  1.1.1.4  christos 		echo "graph_category dns"
    350      1.1  christos 		p_config "num.query.flags.QR" "QR (query reply) flag" "ABSOLUTE"
    351      1.1  christos 		p_config "num.query.flags.AA" "AA (auth answer) flag" "ABSOLUTE"
    352      1.1  christos 		p_config "num.query.flags.TC" "TC (truncated) flag" "ABSOLUTE"
    353      1.1  christos 		p_config "num.query.flags.RD" "RD (recursion desired) flag" "ABSOLUTE"
    354      1.1  christos 		p_config "num.query.flags.RA" "RA (rec avail) flag" "ABSOLUTE"
    355      1.1  christos 		p_config "num.query.flags.Z" "Z (zero) flag" "ABSOLUTE"
    356      1.1  christos 		p_config "num.query.flags.AD" "AD (auth data) flag" "ABSOLUTE"
    357      1.1  christos 		p_config "num.query.flags.CD" "CD (check disabled) flag" "ABSOLUTE"
    358      1.1  christos 		p_config "num.query.edns.present" "EDNS OPT present" "ABSOLUTE"
    359      1.1  christos 		p_config "num.query.edns.DO" "DO (DNSSEC OK) flag" "ABSOLUTE"
    360      1.1  christos 		echo "graph_info This graphs plots the flags inside incoming queries. For example, if QR, AA, TC, RA, Z flags are set, the query can be rejected. RD, AD, CD and DO are legitimately set by some software."
    361      1.1  christos 		;;
    362      1.1  christos 	histogram)
    363      1.1  christos 		echo "graph_title Unbound DNS histogram of reply time"
    364      1.1  christos 		echo "graph_args --base 1000 -l 0"
    365      1.1  christos 		echo "graph_vlabel queries / \${graph_period}"
    366      1.1  christos 		echo "graph_scale no"
    367  1.1.1.4  christos 		echo "graph_category dns"
    368      1.1  christos 		echo hcache.label "cache hits"
    369      1.1  christos 		echo hcache.min 0
    370      1.1  christos 		echo hcache.type ABSOLUTE
    371      1.1  christos 		echo hcache.draw AREA
    372      1.1  christos 		echo hcache.colour 999999
    373      1.1  christos 		echo h64ms.label "0 msec - 66 msec"
    374      1.1  christos 		echo h64ms.min 0
    375      1.1  christos 		echo h64ms.type ABSOLUTE
    376      1.1  christos 		echo h64ms.draw STACK
    377      1.1  christos 		echo h64ms.colour 0000FF
    378      1.1  christos 		echo h128ms.label "66 msec - 131 msec"
    379      1.1  christos 		echo h128ms.min 0
    380      1.1  christos 		echo h128ms.type ABSOLUTE
    381      1.1  christos 		echo h128ms.colour 1F00DF
    382      1.1  christos 		echo h128ms.draw STACK
    383      1.1  christos 		echo h256ms.label "131 msec - 262 msec"
    384      1.1  christos 		echo h256ms.min 0
    385      1.1  christos 		echo h256ms.type ABSOLUTE
    386      1.1  christos 		echo h256ms.draw STACK
    387      1.1  christos 		echo h256ms.colour 3F00BF
    388      1.1  christos 		echo h512ms.label "262 msec - 524 msec"
    389      1.1  christos 		echo h512ms.min 0
    390      1.1  christos 		echo h512ms.type ABSOLUTE
    391      1.1  christos 		echo h512ms.draw STACK
    392      1.1  christos 		echo h512ms.colour 5F009F
    393      1.1  christos 		echo h1s.label "524 msec - 1 sec"
    394      1.1  christos 		echo h1s.min 0
    395      1.1  christos 		echo h1s.type ABSOLUTE
    396      1.1  christos 		echo h1s.draw STACK
    397      1.1  christos 		echo h1s.colour 7F007F
    398      1.1  christos 		echo h2s.label "1 sec - 2 sec"
    399      1.1  christos 		echo h2s.min 0
    400      1.1  christos 		echo h2s.type ABSOLUTE
    401      1.1  christos 		echo h2s.draw STACK
    402      1.1  christos 		echo h2s.colour 9F005F
    403      1.1  christos 		echo h4s.label "2 sec - 4 sec"
    404      1.1  christos 		echo h4s.min 0
    405      1.1  christos 		echo h4s.type ABSOLUTE
    406      1.1  christos 		echo h4s.draw STACK
    407      1.1  christos 		echo h4s.colour BF003F
    408      1.1  christos 		echo h8s.label "4 sec - 8 sec"
    409      1.1  christos 		echo h8s.min 0
    410      1.1  christos 		echo h8s.type ABSOLUTE
    411      1.1  christos 		echo h8s.draw STACK
    412      1.1  christos 		echo h8s.colour DF001F
    413      1.1  christos 		echo h16s.label "8 sec - ..."
    414      1.1  christos 		echo h16s.min 0
    415      1.1  christos 		echo h16s.type ABSOLUTE
    416      1.1  christos 		echo h16s.draw STACK
    417      1.1  christos 		echo h16s.colour FF0000
    418      1.1  christos 		echo "graph_info Histogram of the reply times for queries."
    419      1.1  christos 		;;
    420      1.1  christos 	esac
    421      1.1  christos 
    422      1.1  christos 	exit 0
    423      1.1  christos fi
    424      1.1  christos 
    425      1.1  christos # do the stats itself
    426      1.1  christos get_state
    427      1.1  christos 
    428      1.1  christos # get the time elapsed
    429      1.1  christos get_value "time.elapsed"
    430      1.1  christos if test $value = 0 || test $value = "0.000000"; then
    431      1.1  christos 	echo "error: time elapsed 0 or could not retrieve data"
    432      1.1  christos 	exit 1
    433      1.1  christos fi
    434      1.1  christos elapsed="$value"
    435      1.1  christos 
    436      1.1  christos # print value for $1
    437      1.1  christos print_value ( ) {
    438      1.1  christos 	mn=`echo $1 | sed $ABBREV | tr . _`
    439      1.1  christos 	get_value $1
    440      1.1  christos 	echo "$mn.value" $value
    441      1.1  christos }
    442      1.1  christos 
    443      1.1  christos # print value if line already found in $2
    444      1.1  christos print_value_line ( ) {
    445      1.1  christos 	mn=`echo $1 | sed $ABBREV | tr . _`
    446      1.1  christos 	value="`echo $2 | sed -e 's/^.*=//'`"
    447      1.1  christos 	echo "$mn.value" $value
    448      1.1  christos }
    449      1.1  christos 
    450      1.1  christos 
    451      1.1  christos case $id in
    452      1.1  christos hits)
    453      1.1  christos 	for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state |
    454      1.1  christos 		sed -e 's/=.*//'` total.num.queries \
    455      1.1  christos 		total.num.cachehits total.num.prefetch num.query.tcp \
    456  1.1.1.4  christos 		num.query.tcpout num.query.udpout num.query.tls num.query.tls.resume \
    457  1.1.1.3  christos 		num.query.ipv6 unwanted.queries \
    458      1.1  christos 		unwanted.replies; do
    459      1.1  christos 		if grep "^"$x"=" $state >/dev/null 2>&1; then
    460      1.1  christos 			print_value $x
    461      1.1  christos 		fi
    462      1.1  christos 	done
    463      1.1  christos 	;;
    464      1.1  christos queue)
    465      1.1  christos 	for x in total.requestlist.avg total.requestlist.max \
    466      1.1  christos 		total.requestlist.overwritten total.requestlist.exceeded; do
    467      1.1  christos 		print_value $x
    468      1.1  christos 	done
    469      1.1  christos 	;;
    470      1.1  christos memory)
    471      1.1  christos 	for x in mem.cache.rrset mem.cache.message mem.mod.iterator \
    472      1.1  christos 		mem.mod.validator msg.cache.count rrset.cache.count \
    473      1.1  christos 		infra.cache.count key.cache.count; do
    474      1.1  christos 		print_value $x
    475      1.1  christos 	done
    476      1.1  christos 	;;
    477      1.1  christos by_type)
    478  1.1.1.4  christos 	for nm in `grep "^num.query.type" $seentags`; do
    479  1.1.1.4  christos 		print_value $nm
    480      1.1  christos 	done
    481      1.1  christos 	;;
    482      1.1  christos by_class)
    483  1.1.1.4  christos 	for nm in `grep "^num.query.class" $seentags`; do
    484  1.1.1.4  christos 		print_value $nm
    485      1.1  christos 	done
    486      1.1  christos 	;;
    487      1.1  christos by_opcode)
    488  1.1.1.4  christos 	for nm in `grep "^num.query.opcode" $seentags`; do
    489  1.1.1.4  christos 		print_value $nm
    490      1.1  christos 	done
    491      1.1  christos 	;;
    492      1.1  christos by_rcode)
    493  1.1.1.4  christos 	for nm in `grep "^num.answer.rcode" $seentags`; do
    494  1.1.1.4  christos 		print_value $nm
    495      1.1  christos 	done
    496      1.1  christos 	print_value "num.answer.secure"
    497      1.1  christos 	print_value "num.answer.bogus"
    498      1.1  christos 	print_value "num.rrset.bogus"
    499      1.1  christos 	;;
    500      1.1  christos by_flags)
    501      1.1  christos 	for x in num.query.flags.QR num.query.flags.AA num.query.flags.TC num.query.flags.RD num.query.flags.RA num.query.flags.Z num.query.flags.AD num.query.flags.CD num.query.edns.present num.query.edns.DO; do
    502      1.1  christos 		print_value $x
    503      1.1  christos 	done
    504      1.1  christos 	;;
    505      1.1  christos histogram)
    506      1.1  christos 	get_value total.num.cachehits
    507      1.1  christos 	echo hcache.value $value
    508      1.1  christos 	r=0
    509      1.1  christos 	for x in histogram.000000.000000.to.000000.000001 \
    510      1.1  christos 		histogram.000000.000001.to.000000.000002 \
    511      1.1  christos 		histogram.000000.000002.to.000000.000004 \
    512      1.1  christos 		histogram.000000.000004.to.000000.000008 \
    513      1.1  christos 		histogram.000000.000008.to.000000.000016 \
    514      1.1  christos 		histogram.000000.000016.to.000000.000032 \
    515      1.1  christos 		histogram.000000.000032.to.000000.000064 \
    516      1.1  christos 		histogram.000000.000064.to.000000.000128 \
    517      1.1  christos 		histogram.000000.000128.to.000000.000256 \
    518      1.1  christos 		histogram.000000.000256.to.000000.000512 \
    519      1.1  christos 		histogram.000000.000512.to.000000.001024 \
    520      1.1  christos 		histogram.000000.001024.to.000000.002048 \
    521      1.1  christos 		histogram.000000.002048.to.000000.004096 \
    522      1.1  christos 		histogram.000000.004096.to.000000.008192 \
    523      1.1  christos 		histogram.000000.008192.to.000000.016384 \
    524      1.1  christos 		histogram.000000.016384.to.000000.032768 \
    525      1.1  christos 		histogram.000000.032768.to.000000.065536; do
    526      1.1  christos 		get_value $x
    527      1.1  christos 		r=`expr $r + $value`
    528      1.1  christos 	done
    529      1.1  christos 	echo h64ms.value $r
    530      1.1  christos 	get_value histogram.000000.065536.to.000000.131072
    531      1.1  christos 	echo h128ms.value $value
    532      1.1  christos 	get_value histogram.000000.131072.to.000000.262144
    533      1.1  christos 	echo h256ms.value $value
    534      1.1  christos 	get_value histogram.000000.262144.to.000000.524288
    535      1.1  christos 	echo h512ms.value $value
    536      1.1  christos 	get_value histogram.000000.524288.to.000001.000000
    537      1.1  christos 	echo h1s.value $value
    538      1.1  christos 	get_value histogram.000001.000000.to.000002.000000
    539      1.1  christos 	echo h2s.value $value
    540      1.1  christos 	get_value histogram.000002.000000.to.000004.000000
    541      1.1  christos 	echo h4s.value $value
    542      1.1  christos 	get_value histogram.000004.000000.to.000008.000000
    543      1.1  christos 	echo h8s.value $value
    544      1.1  christos 	r=0
    545      1.1  christos 	for x in histogram.000008.000000.to.000016.000000 \
    546      1.1  christos 		histogram.000016.000000.to.000032.000000 \
    547      1.1  christos 		histogram.000032.000000.to.000064.000000 \
    548      1.1  christos 		histogram.000064.000000.to.000128.000000 \
    549      1.1  christos 		histogram.000128.000000.to.000256.000000 \
    550      1.1  christos 		histogram.000256.000000.to.000512.000000 \
    551      1.1  christos 		histogram.000512.000000.to.001024.000000 \
    552      1.1  christos 		histogram.001024.000000.to.002048.000000 \
    553      1.1  christos 		histogram.002048.000000.to.004096.000000 \
    554      1.1  christos 		histogram.004096.000000.to.008192.000000 \
    555      1.1  christos 		histogram.008192.000000.to.016384.000000 \
    556      1.1  christos 		histogram.016384.000000.to.032768.000000 \
    557      1.1  christos 		histogram.032768.000000.to.065536.000000 \
    558      1.1  christos 		histogram.065536.000000.to.131072.000000 \
    559      1.1  christos 		histogram.131072.000000.to.262144.000000 \
    560      1.1  christos 		histogram.262144.000000.to.524288.000000; do
    561      1.1  christos 		get_value $x
    562      1.1  christos 		r=`expr $r + $value`
    563      1.1  christos 	done
    564      1.1  christos 	echo h16s.value $r
    565      1.1  christos 	;;
    566      1.1  christos esac
    567