#! /bin/sh # graph collected DCC statistics in .png files. # [-x] debugging # [-q] quiet # [-B] make big graphs # [-G db] generate graphs of database sizes # [-G traffic-noratio] database sizes without spam ratios # [-G traffic] mail message rates and spam ratios # [-G ratio] spam ratios # [-h dcc_homedir] # [-T @RRDTOOL@] # see http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/ # or the FreeBSD package. # [-O rrdopts] additional rrdtool options for all graphs # [-t title] for graphs; '%1' is replaced with the type of graph # [-s span] time covered by graphs. # The default is "1day,1week,1month,1year" # [-S stop-epoch] end of the graph # gname basic file name for graphs, - for stdout # rrd1,... RRD databases that will be combined to produce the graphs # The rrd files must be initialzed with dcc-stats-init, which is called # automatically by dcc-stats-collect. Data must be collected very # 10 minutes with dcc-stats-collect. The rrd files should be in # /var/dcc/stats # Copyright (c) 2006 by Rhyolite Software, LLC # # This agreement is not applicable to any entity which sells anti-spam # solutions to others or provides an anti-spam solution as part of a # security solution sold to other entities, or to a private network # which employs the DCC or uses data provided by operation of the DCC # but does not provide corresponding data to other users. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # Parties not eligible to receive a license under this agreement can # obtain a commercial license to use DCC and permission to use # U.S. Patent 6,330,590 by contacting Commtouch at http://www.commtouch.com/ # or by email to nospam@commtouch.com. # # A commercial license would be for Distributed Checksum and Reputation # Clearinghouse software. That software includes additional features. This # free license for Distributed ChecksumClearinghouse Software does not in any # way grant permision to use Distributed Checksum and Reputation Clearinghouse # software # # THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC # BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. # Rhyolite Software DCC 1.3.50-1.46 $Revision$ # @configure_input@ DCC_HOMEDIR=@prefix@ DEBUG= # check the args once to get the home directory while getopts "xqBdRmh:G:T:O:t:s:S:" c; do case $c in x) set -x; DEBUG=-x=;; h) DCC_HOMEDIR="$OPTARG";; *) ;; esac done . $DCC_HOMEDIR/dcc_conf QUIET= ATTRIBS="--width 200 --height 40" AVGFMT="%.1lf %S" M_YGRID="--alt-y-mrtg" P_YGRID="--y-grid 25:2" H_YGRID="--alt-y-mrtg" XYEAR_MONTHS=2 GRAPH_DB= GRAPH_TRAFFIC= GRAPH_RATIO= GRAPH_SET= RRDOPTS= RRDTOOL=@RRDTOOL@ TITLE_SET= SPANS="1day,1week,1month,1year" STOP= USAGE="`basename $0`: [-xqB] [-h homedir] [-T rrdtool] [-O rrdopts] [-G type] [t title] [-s spans] [-S stop-epoch] gname rrd1 rrd2 rrd3 ..." OPTIND=1 while getopts "xqBdRmh:G:T:O:t:s:S:" c; do case $c in x) ;; q) QUIET="-q";; h) ;; B) ATTRIBS="--width 600 --height 240"; AVGFMT="%.0lf/day" M_YGRID= P_YGRID= H_YGRID="--alt-autoscale-max" XYEAR_MONTHS=1;; d) GRAPH_SET=yes; GRAPH_DB=yes;; # obsolete R) GRAPH_RATIO=;; # obsolete m) GRAPH_SET=yes; GRAPH_TRAFFIC=yes; GRAPH_RATIO=yes;; # obsolete G) GRAPH_SET=yes case "$OPTARG" in db) GRAPH_DB=yes;; traffic-noratio) GRAPH_TRAFFIC=yes;; traffic) GRAPH_TRAFFIC=yes; GRAPH_RATIO=yes;; ratio) GRAPH_RATIO=yes;; *) echo "$USAGE" 1>&2; exit 1;; esac ;; T) RRDTOOL="$OPTARG";; O) RRDOPTS="$RRDOPTS $OPTARG";; t) TITLE_SET=yes; TITLE_PAT="$OPTARG";; s) SPANS="$OPTARG";; S) if expr "$OPTARG" : '[0-9]*$' >/dev/null \ && test "$OPTARG" -gt 1033870038 \ -a "$OPTARG" -lt 2000000000; then STOP=$OPTARG else echo "$OPTARG is a bad number of seconds since the Epoch" 1>&2 exit 1; fi ;; *) echo "$USAGE" 1>&2; exit 1;; esac done shift `expr $OPTIND - 1 || true` if test "$#" -lt 1; then echo "$USAGE" 1>&2 exit 1 fi if test -z "$GRAPH_SET"; then GRAPH_RATIO=yes # bug compatible with old versions fi cd $DCC_HOMEDIR/stats GNAME=$1 if test -n "$QUIET"; then exec 1>/dev/null fi if test "$#" -ge 2; then # assume .rrd file is same as graph name if absent shift fi if test "$TITLE_SET" != yes; then if test "X$GNAME" != X-; then TITLE_PAT="%1 at $GNAME" else TITLE_PAT="%1" fi fi # find the number of databases, the latest timestamp among the databases, # and rrdtool expressions to combine the databases NDBS=0 MAX_LAST=0 STEP=1 CDEF_reports="CDEF:reports=Ureports,UNKN" CDEF_bulk="CDEF:bulk=Ubulk,UNKN" CDEF_spam="CDEF:spam=Uspam,UNKN" while test $# -gt 0; do FILE=$1; shift if test "$FILE" = "`basename $FILE .rrd`"; then # this round-about tactic expands "*.foo.com" set -- $FILE.rrd $* continue fi NDBS=`expr $NDBS + 1` LAST_FILE="$FILE" LAST=`$RRDTOOL last $FILE` if test "0$LAST" -gt $MAX_LAST; then MAX_LAST=$LAST fi NSTEP=`$RRDTOOL info $FILE | sed -n -e 's/^step = \([0-9][0-9]*\)/\1/p'` if test 0$NSTEP -gt $STEP; then STEP=$NSTEP fi for type in reports bulk spam; do eval DEFS_$type='"$DEFS_'$type DEF:$type$NDBS=$FILE:$type:AVERAGE'"' # When we sum data, count missing data as 0 instead of as unknown. if test "$NDBS" -eq 1; then eval CDEF_U$type='"CDEF:'U$type=${type}1,UN'"' eval CDEF_$type='"$CDEF_'$type,$type$NDBS,UN,0,$type$NDBS,IF'"' else eval CDEF_U$type='"$CDEF_'U$type,$type$NDBS',UN,*"' eval CDEF_$type='"$CDEF_'$type,$type$NDBS,UN,0,$type$NDBS,IF,+'"' fi done done CDEF_reports="$CDEF_reports,IF" CDEF_bulk="$CDEF_bulk,IF" CDEF_spam="$CDEF_spam,IF" # find good ending dates if test "$MAX_LAST" -ne 0; then if test -n "$STOP" -a "$MAX_LAST" -gt 0"$STOP"; then MAX_LAST="$STOP" fi # avoid odd times when individual servers were polled MAX_LAST=`expr $MAX_LAST - $MAX_LAST % $STEP` LAST=`expr $LAST - $LAST % $STEP` if TS="`date -r $MAX_LAST '+%x %R %Z' 2>/dev/null`"; then : ; else # deal with systems that do not have `date -r` TS="`@PERL@ -e 'use POSIX qw(strftime); \ print strftime "%x %R %Z", localtime(time());'`" fi if test -z "`$RRDTOOL version | grep '^RRDtool 1\.0'`"; then TS=`echo "$TS" | sed -e 's/:/\\\:/g'` fi END=$MAX_LAST DB_END=`expr $MAX_LAST - $MAX_LAST % 86400` else DB_END="now" END="now" fi FTYPE=png ATTRIBS="$ATTRIBS --imgformat PNG" for DUR in `echo $SPANS | tr ',' ' '`; do case $DUR in 1d*) DUR=1day SPAN=24h XGRID="--x-grid HOUR:1:HOUR:2:HOUR:2:0:%k" # as the "rdtool graph" man page suggests, don't be fooled # by daylight savings time ;; 1w*) DUR=1week SPAN=168h # 24*3600 = 86400 XGRID="--x-grid HOUR:6:DAY:1:DAY:1:86400:%a" # as the "rdtool graph" man page suggests, don't be fooled # by daylight savings time ;; 1m*) DUR=1month SPAN=$DUR XGRID="--x-grid WEEK:1:WEEK:1:WEEK:1:0:%b/%d" ;; 1y*) DUR=1year SPAN=$DUR # label every month on big graphs and every other on small # 28*24*60*60 = 2419200 XGRID="--x-grid MONTH:1:YEAR:1:MONTH:$XYEAR_MONTHS:2419200:%b" ;; 2y*) DUR=2years SPAN=$DUR if test "$XYEAR_MONTHS" = 2; then # small graph with 1 label/year # 365*24*60*60 = 31536000 = year XGRID="--x-grid YEAR:1:YEAR:1:YEAR:1:31536000:%Y" else # label every other month on big graphs # 28*24*60*60 = 2419200 XYEAR_MONTHS=2 XGRID="--x-grid MONTH:1:YEAR:1:MONTH:2:2419200:%b" fi ;; *) case $DUR in 3y*) DUR=3years;; 4y*) DUR=4years;; # assume everything else is the 5 year maximum in the RRD files *) DUR=5years;; esac SPAN=$DUR if test "$XYEAR_MONTHS" = 2; then # small graph with 1 label/year # 365*24*60*60 = 31536000 = year XGRID="--x-grid YEAR:1:YEAR:1:YEAR:1:31536000:%Y" else # big graph with 1 label/year XGRID="--x-grid MONTH:1:MONTH:12:MONTH:12:0:%b/%y" fi ;; esac ONAME=- if test "$GRAPH_RATIO" = yes; then if test "X$GNAME" != X-; then ONAME=$GNAME-spam-ratio.$DUR.$FTYPE if test -z "$QUIET"; then echo "$ONAME: " | tr -d '\012' 1>&2 fi fi TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Spam Ratio/g'` $RRDTOOL graph $ONAME $RRDOPTS \ --end $END --start end-$SPAN \ $ATTRIBS --title "$TITLE" \ $XGRID $P_YGRID \ --unit '%%' --lower-limit 0 --upper-limit 100 \ $DEFS_reports $DEFS_bulk $DEFS_spam \ "$CDEF_Ureports" "$CDEF_Ubulk" "$CDEF_Uspam" \ "$CDEF_reports" "$CDEF_bulk" "$CDEF_spam" \ 'CDEF:percentbulk=bulk,reports,/,100,*,0,100,LIMIT' \ 'CDEF:percentspam=spam,reports,/,100,*,0,100,LIMIT' \ 'AREA:percentbulk#cc0000:likely spam' \ 'AREA:percentspam#ffb6c1:trapped spam\j' \ 'GPRINT:percentbulk:AVERAGE:average %.0lf%% ' \ "COMMENT:$TS\j" if test "X$GNAME" = X-; then exit fi fi if test "$GRAPH_TRAFFIC" = yes; then if test "X$GNAME" != X-; then ONAME=$GNAME-spam.$DUR.$FTYPE if test -z "$QUIET"; then echo "$ONAME: " | tr -d '\012' 1>&2 fi fi TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Mail Checked/g'` $RRDTOOL graph $ONAME $RRDOPTS \ --end $END --start end-$SPAN \ $ATTRIBS --title "$TITLE" \ $XGRID $M_YGRID \ --vertical-label "msgs/day" \ $DEFS_bulk $DEFS_spam $DEFS_reports \ "$CDEF_Ureports" "$CDEF_Ubulk" "$CDEF_Uspam" \ "$CDEF_reports,86400,*" "$CDEF_bulk,86400,*" \ "$CDEF_spam,86400,*" \ 'AREA:reports#87cefa:total mail' \ 'AREA:bulk#cc0000:likely spam' \ 'AREA:spam#ffb6c1:trapped spam\j' \ "GPRINT:reports:AVERAGE:average $AVGFMT" \ "GPRINT:bulk:AVERAGE:$AVGFMT" \ "COMMENT:$TS\j" if test "X$GNAME" = X-; then exit fi fi # the other graphs have resolutions only to days if test "$DUR" = 1day; then continue fi if test "$GRAPH_DB" = yes; then if test "X$GNAME" != X-; then ONAME=$GNAME-hashes.$DUR.$FTYPE if test -z "$QUIET"; then echo "$ONAME: " | tr -d '\012' 1>&2 fi fi TITLE=`echo "$TITLE_PAT" | sed -e 's/%1/Checksums/g'` # take the database values from the last server $RRDTOOL graph $ONAME $RRDOPTS \ --end $DB_END --start end-$SPAN \ $ATTRIBS --step 86400 --title "$TITLE" \ $XGRID $H_YGRID -l 0 \ DEF:hashes=$LAST_FILE:hashes:MIN \ 'AREA:hashes#ffb6c1:' \ "COMMENT:$TS\c" fi done