#!/bin/sh # -*- sh -*- : << =cut =head1 NAME dspam_activity - Plugin to monitor DSPAM message handling activities. =head1 APPLICABLE SYSTEMS Any system running a recent (3.8.0 or higher) DSPAM install. =head1 CONFIGURATION The plugin uses the contents of the SystemLog or UserLog produced by DSPAM. The following environment variables are used by this plugin: logfile - Where to find the system.log that is written by dspam (default: /var/spool/dspam/system.log) =head2 CONFIGURATION EXAMPLES [dspam_activity] env.logfile /opt/dspam/var/spool/dspam/system.log # or when monitoring only a single user in stead of all users: env.logfile /var/spool/dspam/data/example.org/username/username.log =head1 USAGE Link this plugin to /etc/munin/plugins/ and restart the munin-node. You'll need to enable system logging in dspam.conf, set 'SystemLog on' in the DSPAM configuration file. =head1 INTERPRETATION The graph shows the messages that DSPAM has processed over the monitored period, and what kind of action was taken on it. Possible activities are: Received messages can be classified as: - Innocent (I) - Spam (S) - Auto-whitelist (W) - Virus (V) - Blocklist (O) - Blacklist (RBL) (A) Other actions: - Retrained as spam (M) - Retrained as innocent (F) - Inoculation (N) - Corpusfed (C) Please see DSPAM documentation for more information on used terminology. The single character in parentheses is the DSPAM internal name for the classifications. =head1 AUTHOR Copyright 2010-2011 Tom Hendrikx =head1 LICENSE GPLv2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. =head1 BUGS None known. Please report to author when you think you found something. =head2 TODO LIST =head1 VERSION $Id: dspam_activity 139 2011-08-04 20:03:22Z tomhendr $ =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =cut # defaults for configurable settings : ${logfile:=/var/spool/dspam/system.log} : ${statefile:=$MUNIN_STATEFILE} # include munin plugin helper . $MUNIN_LIBDIR/plugins/plugin.sh ########################## # Some generic functions # ########################## # # debug $message # Prints debugging output when munin-run is called with --pidebug argument (i.e. when MUNIN_DEBUG is set) # debug() { if [ -n "$MUNIN_DEBUG" ]; then echo "# DEBUG: $@" fi } # # get_activity_description $activity $type # Return textual descriptions for the various activities # get_activity_description() { local activity=$1 local type=$2 # defaults local short="Unknown ($activity)" local long="Unknown ($activity)" # Possible activities: I S W V O A M F N C case $activity in I) short=Innocent long="Messages received and classified as innocent" ;; S) short=Spam long="Messages received and classified as spam" ;; W) short=Auto-whitelisted long="Messages received and auto-whitelisted" ;; V) short=Virus long="Messages received and classified as virus by Clamav" ;; O) short=Blocklisted long="Messages received but not classified because the sender domain is on to the user blocklist" ;; A) short="Blacklisted (RBL)" long="Message received and classified as spam because the sender ip is listed on the RBL" ;; M) short="Retrained as spam" long="Messages classified as innocent, but retrained by user as spam" ;; F) short="Retrained as innocent" long="Messages classified as spam, but retrained by the user as innocent" ;; N) short=Inoculation long="Messages trained as spam through inoculation" ;; C) short=Corpusfed long="Messages fed from a corpus" ;; esac [ "$type" = "short" ] && echo $short && return [ "$type" = "long" ] && echo $long && return } ######################################## # Functions that generate munin output # ######################################## # # print_autoconf # Output for 'munin-node-configure autoconf' functionality # print_autoconf() { if [ ! -r $logfile ]; then echo "no (logfile $logfile does not exist or not readable)" else echo yes fi } # # print_config # Output for 'munin-run config' command. # print_config() { debug printing config echo "graph_title DSPAM activity" echo graph_category spamfilter echo graph_args --base 1000 echo graph_vlabel Messages / \${graph_period} echo graph_period minute for activity in I S W V O A M F N C; do local label="$(get_activity_description $activity short)" local info="$(get_activity_description $activity long)" echo $activity.label $label echo $activity.info $info echo $activity.draw AREASTACK echo $activity.type DERIVE echo $activity.min 0 done debug finished printing config } # # print_fetch # Output for 'munin-run fetch' command: the actual data to graph. # print_fetch() { debug printing fetch local old_ts [ -r $statefile ] && old_ts=$(cat $statefile) if [ -n "$old_ts" ]; then debug read timestamp $old_ts from statefile # sample from system.log: # 1285144434M"Dr.Abdul Qahaar" 2,4c99980137698241679684 \ # Business Proposal / Partnership Investment1.256280username@example.orgRetrained<421586.75972.qm@web120402.mail.ne1.yahoo.com> if [ -r $logfile ]; then # Possible activities: I S W V O A M F N C local aI=0 aS=0 aW=0 aV=0 aO=0 aA=0 aM=0 aF=0 aN=0 aC=0 local skipped=0 processed=0 local old_IFS=$IFS IFS=" " # tab-separator in $logfile while read ts activity from signature subject x recipient info msgid; do if ! [ $ts -gt 0 2> /dev/null ]; then debug skipped entry with non-numeric timestamp: $ts elif [ $ts -gt $old_ts ]; then debug processing entry with timestamp $ts, activity=$activity, subject=$subject, msgid=$msgid case $activity in I) aI=$((aI + 1)) ;; S) aS=$((aS + 1)) ;; W) aW=$((aW + 1)) ;; V) aV=$((aV + 1)) ;; O) aO=$((aO + 1)) ;; A) aA=$((aA + 1)) ;; M) aM=$((aM + 1)) ;; F) aF=$((aF + 1)) ;; N) aN=$((aN + 1)) ;; C) aC=$((aC + 1)) ;; *) debug unknown activity $activity found, subject=$subject, msgid=$msgid ;; esac processed=$((processed + 1)) else skipped=$((skipped + 1)) fi done < $logfile IFS=$old_IFS debug skipped $skipped lines in logfile because timestamp was too old debug processed $processed lines in logfile # show results echo I.value $aI echo S.value $aS echo W.value $aW echo V.value $aV echo O.value $aO echo A.value $aA echo M.value $aM echo F.value $aF echo N.value $aN echo C.value $aC else debug logfile not available $logfile exit 66 # EX_NOINPUT fi else debug could not read timestamp from statefile # no exit here, we need the next operation to write a timestamp in the statefile fi # update statefile with current timestamp local new_ts=$(date +%s) echo $new_ts > $statefile debug timestamp in statefile updated to $new_ts, old was $old_ts debug finished printing fetch } ##################### # Main process loop # ##################### # show env settings debug dspam_activity plugin started, pid=$$ debug settings: debug - logfile is set to: $logfile debug - statefile is set to: $statefile command=$1 [ -n "$command" ] || command="fetch" debug - command is set to: $command debug settings completed, starting process case $command in autoconf) print_autoconf ;; config) print_config ;; fetch) print_fetch ;; esac debug exiting exit 0 # EX_OK