root / plugins / dspam / dspam_ @ 8589c6df
Historique | Voir | Annoter | Télécharger (20,2 ko)
| 1 | 429819cf | Tom Hendrikx | #!/bin/sh |
|---|---|---|---|
| 2 | # -*- sh -*- |
||
| 3 | |||
| 4 | : << =cut |
||
| 5 | |||
| 6 | =head1 NAME |
||
| 7 | |||
| 8 | dspam_ - Plugin to monitor various aspects of DSPAM performance |
||
| 9 | |||
| 10 | =head1 APPLICABLE SYSTEMS |
||
| 11 | |||
| 12 | Any system running a recent (3.8.0 or higher) DSPAM install. |
||
| 13 | |||
| 14 | =head1 CONFIGURATION |
||
| 15 | |||
| 16 | The plugin uses the output of the dspam_stats command, which is usually part |
||
| 17 | of any DSPAM install. You'll need to run this plugin as a user that has enough |
||
| 18 | rights to run dspam_stats and generate data for all users. This means that the |
||
| 19 | plugin needs to be run either as root, or as a user that has read access to |
||
| 20 | dspam.conf, and is added as a Trusted user in dspam.conf. |
||
| 21 | |||
| 22 | The following environment variables are used by this plugin: |
||
| 23 | |||
| 24 | dspam_stats - Where to find the dspam_stats binary when it's not in |
||
| 25 | $PATH (default: find anywhere in $PATH). |
||
| 26 | statefile - Where to read/write the statefile that is used to store |
||
| 27 | dspam_stats output |
||
| 28 | (default: $MUNIN_PLUGSTATE/dspam.state). |
||
| 29 | warning - When to trigger a warning (default: 95:). |
||
| 30 | critical - When to trigger a critical (default: 90:). |
||
| 31 | pattern - A pattern that is passed to grep in order to find the |
||
| 32 | DSPAM uids to display. When this variable is set, the |
||
| 33 | value of target (see USAGE) is ignored (default: empty). |
||
| 34 | description - A string describing the set of uids selected by |
||
| 35 | above pattern (default: empty). |
||
| 36 | |||
| 37 | Warning and critical values can also set on a DSPAM uid basis, use Munins |
||
| 38 | internal format for the DSPAM uid for this notation (see CONFIGURATION |
||
| 39 | EXAMPLES and USAGE for details). |
||
| 40 | |||
| 41 | =head2 CONFIGURATION EXAMPLES |
||
| 42 | |||
| 43 | [dspam*] |
||
| 44 | user root |
||
| 45 | env.dspam_stats /opt/dspam/bin/dspam_stats |
||
| 46 | env.statefile /tmp/dspam.state |
||
| 47 | |||
| 48 | [dspam_accuracy*] |
||
| 49 | env.critical 95: |
||
| 50 | env.warning 96: |
||
| 51 | |||
| 52 | # raise warning level for username@example.org |
||
| 53 | env.username_example_org_warning 97: |
||
| 54 | |||
| 55 | # show all accounts from one domain |
||
| 56 | env.pattern @example\.org |
||
| 57 | env.description domain example.org |
||
| 58 | |||
| 59 | =head1 USAGE |
||
| 60 | |||
| 61 | Link this plugin to /etc/munin/plugins/ and restart the munin-node. The link |
||
| 62 | should be in the format: dspam_<graph>_<target>, where: |
||
| 63 | |||
| 64 | graph - One of: accuracy, processed, processed_abs. |
||
| 65 | target - The uid that DSPAM generates in dspam_stats output, |
||
| 66 | but converted to Munin internal name format. Normally |
||
| 67 | this means that non-alphabetic and non-numeral characters |
||
| 68 | are replaced by an underscore. For example, |
||
| 69 | username@example.org will become username_example_org. |
||
| 70 | A special case is uid ALL, which will draw a graph for |
||
| 71 | a total of all uids, or for a list of all uids (depending |
||
| 72 | on the graph type). |
||
| 73 | NB For advanced uid selection such as 'all users of domain |
||
| 74 | example.org', please see the environment variable 'pattern' |
||
| 75 | under CONFIGURATION. |
||
| 76 | |||
| 77 | =head1 INTERPRETATION |
||
| 78 | |||
| 79 | The plugin supports the following graph types: |
||
| 80 | |||
| 81 | accuracy - Shows the overall accuracy of all users as a |
||
| 82 | percentage. The overall accuracy is the number of |
||
| 83 | correctly classified messages (both ham and spam) in |
||
| 84 | relation to the number of all processed messages. |
||
| 85 | |||
| 86 | 8589c6df | klemens | absprocessed - Shows the absolute numbers of messages processed, |
| 87 | 429819cf | Tom Hendrikx | sorted by the classification that DSPAM uses. The |
| 88 | numbers are stacked, making the height of the column |
||
| 89 | display the increase of processed messages over time. |
||
| 90 | |||
| 91 | processed - Shows the same data as dspam_processed_abs_, but as |
||
| 92 | percentage of the total amount of processed messages, |
||
| 93 | making it clear to see how the amounts of classified |
||
| 94 | messages are divided. |
||
| 95 | |||
| 96 | =head1 AUTHOR |
||
| 97 | |||
| 98 | Copyright 2010 Tom Hendrikx <tom@whyscream.net> |
||
| 99 | |||
| 100 | =head1 LICENSE |
||
| 101 | |||
| 102 | GPLv2 |
||
| 103 | |||
| 104 | This program is free software; you can redistribute it and/or modify |
||
| 105 | it under the terms of the GNU General Public License as published by |
||
| 106 | the Free Software Foundation; version 2 dated June, 1991. |
||
| 107 | |||
| 108 | This program is distributed in the hope that it will be useful, but |
||
| 109 | WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 110 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
| 111 | General Public License for more details. |
||
| 112 | |||
| 113 | You should have received a copy of the GNU General Public License |
||
| 114 | along with this program; if not, write to the Free Software |
||
| 115 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
||
| 116 | 02110-1301 USA. |
||
| 117 | |||
| 118 | =head1 BUGS |
||
| 119 | |||
| 120 | None known. Please report to author when you think you found something. |
||
| 121 | |||
| 122 | =head2 TODO LIST |
||
| 123 | |||
| 124 | Currently developed and tested with bash/dash on linux. |
||
| 125 | More testing might be needed with other shells and OSes. |
||
| 126 | |||
| 127 | =head1 VERSION |
||
| 128 | |||
| 129 | $Id: dspam_ 72 2010-09-15 22:09:15Z tomhendr $ |
||
| 130 | |||
| 131 | =head1 MAGIC MARKERS |
||
| 132 | |||
| 133 | #%# family=auto |
||
| 134 | #%# capabilities=autoconf suggest |
||
| 135 | |||
| 136 | =cut |
||
| 137 | |||
| 138 | # defaults for configurable settings |
||
| 139 | : ${dspam_stats:=$(which dspam_stats 2> /dev/null)}
|
||
| 140 | : ${statefile:=${MUNIN_PLUGSTATE}/dspam.state}
|
||
| 141 | : ${statefile_max_age:=180} # 3 minutes
|
||
| 142 | : ${warning:=95:}
|
||
| 143 | : ${critical:=90:}
|
||
| 144 | |||
| 145 | # include munin plugin helper |
||
| 146 | . $MUNIN_LIBDIR/plugins/plugin.sh |
||
| 147 | |||
| 148 | ####################################### |
||
| 149 | # Some generic file locking functions # |
||
| 150 | ####################################### |
||
| 151 | |||
| 152 | # |
||
| 153 | # file_is_usable $file $max_age |
||
| 154 | # Check if file is OK for usage: existing, readable and not too old |
||
| 155 | # |
||
| 156 | file_is_usable() {
|
||
| 157 | local file=$1 |
||
| 158 | local max_age=$2 |
||
| 159 | local lock=$file.lock |
||
| 160 | |||
| 161 | [ ! -f $file ] && debug statefile $file does not exist && return 66 # EX_NOINPUT |
||
| 162 | [ ! -r $file ] && debug statefile $file is not readable && return 65 # EX_DATAERR |
||
| 163 | |||
| 164 | local mtime=$(stat --format %Y $file) |
||
| 165 | local file_age=$(( $(date +%s) -mtime )) |
||
| 166 | [ $file_age -gt $max_age ] && debug file $file is too old: $file_age seconds && return 65 # EX_DATAERR |
||
| 167 | |||
| 168 | debug file $file is ok, $file_age seconds old |
||
| 169 | return 0 # EX_OK |
||
| 170 | } |
||
| 171 | |||
| 172 | # |
||
| 173 | # file_get_lock $file |
||
| 174 | # Obtain a lock for the named file |
||
| 175 | # |
||
| 176 | file_get_lock() {
|
||
| 177 | local file=$1 |
||
| 178 | local lock=$file.lock |
||
| 179 | |||
| 180 | while file_is_locked $file; do |
||
| 181 | sleep 1 |
||
| 182 | done |
||
| 183 | |||
| 184 | echo $$ > $lock |
||
| 185 | [ $? -gt 0 ] && debug failed to create lockfile $lock && return 73 # EX_CANTCREAT |
||
| 186 | |||
| 187 | debug created lock for $file |
||
| 188 | return 0 # EX_OK |
||
| 189 | } |
||
| 190 | |||
| 191 | # |
||
| 192 | # file_remove_lock $file |
||
| 193 | # Remove a set lockfile for the named file |
||
| 194 | # |
||
| 195 | file_remove_lock() {
|
||
| 196 | local file=$1 |
||
| 197 | local lock=$file.lock |
||
| 198 | |||
| 199 | rm -f $lock |
||
| 200 | [ $? -gt 0 ] && debug failed to remove lockfile $lock && return 69 # EX_UNAVAILABLE |
||
| 201 | |||
| 202 | debug removed lock for file $file |
||
| 203 | return 0 # EX_OK |
||
| 204 | } |
||
| 205 | |||
| 206 | # |
||
| 207 | # file_is_locked $file |
||
| 208 | # Check if a file is locked |
||
| 209 | # |
||
| 210 | file_is_locked() {
|
||
| 211 | local file=$1 |
||
| 212 | local lock=$1.lock |
||
| 213 | |||
| 214 | [ -f $lock ] && debug file $file is locked && return 0 # EX_OK |
||
| 215 | debug file $file is not locked |
||
| 216 | return 69 # EX_UNAVAILABLE |
||
| 217 | } |
||
| 218 | |||
| 219 | #################################### |
||
| 220 | # DSPAM output processing function # |
||
| 221 | #################################### |
||
| 222 | |||
| 223 | # |
||
| 224 | # update_statefile |
||
| 225 | # Read the output of dspam_stats, convert it and write usable data to the statefile |
||
| 226 | # |
||
| 227 | update_statefile() {
|
||
| 228 | |||
| 229 | file_is_usable $statefile $statefile_max_age && return $? # return when all OK |
||
| 230 | ! file_get_lock $statefile && return $? # return when locking failed |
||
| 231 | |||
| 232 | local tmpfile=$(mktemp) |
||
| 233 | debug created tmpfile $tmpfile |
||
| 234 | |||
| 235 | debug starting $dspam_stats -t -S |
||
| 236 | local t_start=$(date +%s) |
||
| 237 | 8cf82404 | Tom Hendrikx | $dspam_stats -t -S | while read a b c d e f g h i j k l m x; do |
| 238 | 429819cf | Tom Hendrikx | |
| 239 | # example of output format (3.9.1 rc1) for each user: |
||
| 240 | #username@example.org |
||
| 241 | # TP: 0 TN: 2147 FP: 0 FN: 53 SC: 0 NC: 0 |
||
| 242 | # SHR: 0.00% HSR: 0.00% OCA: 97.59% |
||
| 243 | |||
| 244 | 8cf82404 | Tom Hendrikx | # or for short user names: |
| 245 | #vmail TP: 1141 TN: 459 FP: 0 FN: 5 SC: 0 NC: 0 |
||
| 246 | # SHR: 99.56% HSR: 0.00% OCA: 99.69% |
||
| 247 | |||
| 248 | 429819cf | Tom Hendrikx | case $a in |
| 249 | TP:) |
||
| 250 | # the 2nd line |
||
| 251 | local tp=$b tn=$d fp=$f fn=$h sc=$j nc=$l |
||
| 252 | ;; |
||
| 253 | SHR:) |
||
| 254 | # the 3rd line |
||
| 255 | local shr=$(echo $b | sed 's/%$//g') |
||
| 256 | local hsr=$(echo $d | sed 's/%$//g') |
||
| 257 | local oca=$(echo $f | sed 's/%$//g') |
||
| 258 | |||
| 259 | # we're done, write data from current user to the statefile |
||
| 260 | local clean_user=$(clean_fieldname $uid) |
||
| 261 | local state="$uid $clean_user $tp $tn $fp $fn $sc $nc $shr $hsr $oca" |
||
| 262 | echo $state >> $tmpfile |
||
| 263 | [ $? -gt 0 ] && debug failed to write data for $uid to tmpfile && return 73 # EX_CANTCREAT |
||
| 264 | debug wrote data for $uid to tmpfile: $state |
||
| 265 | ;; |
||
| 266 | *) |
||
| 267 | # the 1st line |
||
| 268 | local uid=$a |
||
| 269 | 8cf82404 | Tom Hendrikx | # data from 2nd line is also here |
| 270 | [ "$b" = "TP:" ] && local tp=$c tn=$e fp=$g fn=$i sc=$k nc=$m |
||
| 271 | 429819cf | Tom Hendrikx | ;; |
| 272 | esac |
||
| 273 | done |
||
| 274 | local t_end=$(date +%s) |
||
| 275 | debug dspam_stats finished, runtime $((t_end - t_start)) seconds |
||
| 276 | |||
| 277 | mv $tmpfile $statefile |
||
| 278 | [ $? -gt 0 ] && debug failed to move tmpfile to $statefile && return 73 # EX_CANTCREAT |
||
| 279 | debug moved tmpfile to $statefile |
||
| 280 | |||
| 281 | file_remove_lock $statefile |
||
| 282 | |||
| 283 | return 0 # EX_OK |
||
| 284 | } |
||
| 285 | |||
| 286 | |||
| 287 | # |
||
| 288 | # abs2perc |
||
| 289 | # Outputs a percentage calculated from its two arguments |
||
| 290 | # |
||
| 291 | abs2perc() {
|
||
| 292 | # division by zero protection: debug output is merely informal and harmless ;) |
||
| 293 | [ $1 -eq 0 ] && echo 0 && debug abs2perc prevented possible division-by-zero on first argument && return 0 # EX_OK |
||
| 294 | [ $2 -eq 0 ] && echo 0 && debug abs2perc prevented possible division-by-zero on second argument && return 0 # EX_OK |
||
| 295 | |||
| 296 | echo $1 $2 | awk '{ print $1 * 100 / $2 }'
|
||
| 297 | } |
||
| 298 | |||
| 299 | # |
||
| 300 | # debug $output |
||
| 301 | # Prints debugging output when munin-run is called with --pidebug argument (i.e. when MUNIN_DEBUG is set) |
||
| 302 | # |
||
| 303 | debug() {
|
||
| 304 | if [ -n "$MUNIN_DEBUG" ]; then |
||
| 305 | echo "# DEBUG: $@" |
||
| 306 | fi |
||
| 307 | } |
||
| 308 | |||
| 309 | ######################################## |
||
| 310 | # Functions that generate munin output # |
||
| 311 | ######################################## |
||
| 312 | |||
| 313 | # |
||
| 314 | # print_autoconf |
||
| 315 | # Output for 'munin-node-configure' autoconf functionality |
||
| 316 | # |
||
| 317 | print_autoconf() {
|
||
| 318 | if [ -z "$dspam_stats" ]; then |
||
| 319 | echo "no (no dspam_stats binary found)" |
||
| 320 | elif [ ! -x $dspam_stats ]; then |
||
| 321 | echo "no ($dspam_stats found but not executable)" |
||
| 322 | else |
||
| 323 | echo yes |
||
| 324 | fi |
||
| 325 | } |
||
| 326 | |||
| 327 | # |
||
| 328 | # print_suggest |
||
| 329 | # Output for 'munin-node-configure --suggest' |
||
| 330 | # |
||
| 331 | print_suggest() {
|
||
| 332 | echo accuracy_ALL |
||
| 333 | echo processed_ALL |
||
| 334 | echo absprocessed_ALL |
||
| 335 | } |
||
| 336 | |||
| 337 | # |
||
| 338 | # print_config |
||
| 339 | # Output for 'munin-run <plugin> config' command. |
||
| 340 | # |
||
| 341 | print_config() {
|
||
| 342 | debug printing config for graph: $graph |
||
| 343 | |||
| 344 | while file_is_locked $statefile; do |
||
| 345 | debug statefile is locked, waiting |
||
| 346 | sleep 1 |
||
| 347 | done |
||
| 348 | |||
| 349 | case $graph in |
||
| 350 | accuracy) |
||
| 351 | if [ -n "$pattern" ]; then |
||
| 352 | debug env.pattern was set, so use it: $pattern |
||
| 353 | local uid=$description |
||
| 354 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 355 | debug uid_count retrieved from statefile: $uid_count |
||
| 356 | elif [ "$target" = "ALL" ]; then |
||
| 357 | local pattern="-v TOTAL" |
||
| 358 | debug target=ALL: need pattern for all users but not TOTAL: $pattern |
||
| 359 | local uid="all users" |
||
| 360 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 361 | debug uid_count retrieved from statefile: $uid_count |
||
| 362 | else |
||
| 363 | local pattern="\b$target\b" |
||
| 364 | debug target=$target: need pattern for a single user: $pattern |
||
| 365 | local uid=$(grep $pattern $statefile | cut -d' ' -f1) |
||
| 366 | debug retrieved uid value from statefile: $uid |
||
| 367 | local uid_count=1 |
||
| 368 | fi |
||
| 369 | |||
| 370 | echo "graph_title Accuracy for $uid" |
||
| 371 | e00b066f | dipohl | echo graph_category spamfilter |
| 372 | 429819cf | Tom Hendrikx | echo graph_args --base 1000 --upper-limit 100 --rigid |
| 373 | echo graph_vlabel Accuracy in % |
||
| 374 | echo "graph_info This graph shows the current DSPAM Overall Accuracy for $uid ($uid_count uids). Overall Accuracy is the percentage of messages that is classified correctly as either ham or spam." |
||
| 375 | |||
| 376 | debug starting grep for user data in statefile |
||
| 377 | local t_start=$(date +%s) |
||
| 378 | grep $pattern $statefile | while read uid clean_user x; do |
||
| 379 | echo $clean_user.label $uid |
||
| 380 | print_warning $clean_user |
||
| 381 | print_critical $clean_user |
||
| 382 | done |
||
| 383 | local t_end=$(date +%s) |
||
| 384 | debug grep finished, runtime $((t_end - t_start)) seconds |
||
| 385 | |||
| 386 | ;; |
||
| 387 | |||
| 388 | processed) |
||
| 389 | if [ -n "$pattern" ]; then |
||
| 390 | debug env.pattern was set, so use it: $pattern |
||
| 391 | local uid=$description |
||
| 392 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 393 | debug uid_count retrieved from statefile: $uid_count |
||
| 394 | elif [ "$target" = "ALL" ]; then |
||
| 395 | local pattern="-v TOTAL" |
||
| 396 | debug target=ALL: need pattern for all users but not TOTAL: $pattern |
||
| 397 | local uid="all users" |
||
| 398 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 399 | debug uid_count retrieved from statefile: $uid_count |
||
| 400 | else |
||
| 401 | local pattern="\b$target\b" |
||
| 402 | debug target=$target: need pattern for a single user: $pattern |
||
| 403 | local uid=$(grep $pattern $statefile | cut -d' ' -f1) |
||
| 404 | debug retrieved uid value from statefile: $uid |
||
| 405 | local uid_count=1 |
||
| 406 | fi |
||
| 407 | |||
| 408 | echo "graph_title Processed messages for $uid (%)" |
||
| 409 | e00b066f | dipohl | echo graph_category spamfilter |
| 410 | 429819cf | Tom Hendrikx | echo graph_args --base 1000 --upper-limit 100 --rigid |
| 411 | echo graph_vlabel Messages in % |
||
| 412 | echo "graph_info This graph shows the messages that DSPAM processed for $uid ($uid_count uids) in percentages of all processed messages. Messages are divided in the following categories: true positives/negatives, false positives/negatives, and corpusfed ham/spam." |
||
| 413 | echo tp.label True positives |
||
| 414 | echo tp.info Spam messages correctly classified as spam. |
||
| 415 | echo tp.draw AREASTACK |
||
| 416 | echo tn.label True negatives |
||
| 417 | echo tn.info Ham messages correctly classified as ham. |
||
| 418 | echo tn.draw AREASTACK |
||
| 419 | echo fp.label False positives |
||
| 420 | echo fp.info Ham messages incorrectly classified as spam, but corrected by the user. |
||
| 421 | echo fp.draw AREASTACK |
||
| 422 | echo fn.label False negatives |
||
| 423 | echo fn.info Spam messages incorrectly classified as ham, but corrected by the user. |
||
| 424 | echo fn.draw AREASTACK |
||
| 425 | echo sc.label Corpusfed spam |
||
| 426 | echo sc.info Spam messages from a collected corpus for training purposes. |
||
| 427 | echo sc.draw AREASTACK |
||
| 428 | echo nc.label Corpusfed ham |
||
| 429 | echo nc.info Ham messages from a collected corpus for training purposes. |
||
| 430 | echo nc.draw AREASTACK |
||
| 431 | ;; |
||
| 432 | |||
| 433 | absprocessed) |
||
| 434 | if [ -n "$pattern" ]; then |
||
| 435 | debug env.pattern was set, so use it: $pattern |
||
| 436 | local uid=$description |
||
| 437 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 438 | debug uid_count retrieved from statefile: $uid_count |
||
| 439 | elif [ "$target" = "ALL" ]; then |
||
| 440 | local pattern="-v TOTAL" |
||
| 441 | debug target=ALL: need pattern for all users but not TOTAL: $pattern |
||
| 442 | local uid="all users" |
||
| 443 | local uid_count=$(grep $pattern $statefile | wc -l) |
||
| 444 | debug uid_count retrieved from statefile: $uid_count |
||
| 445 | else |
||
| 446 | local pattern="\b$target\b" |
||
| 447 | debug target=$target: need pattern for a single user: $pattern |
||
| 448 | local uid=$(grep $pattern $statefile | cut -d' ' -f1) |
||
| 449 | debug retrieved uid value from statefile: $uid |
||
| 450 | local uid_count=1 |
||
| 451 | fi |
||
| 452 | |||
| 453 | echo "graph_title Processed messages for $uid" |
||
| 454 | e00b066f | dipohl | echo graph_category spamfilter |
| 455 | 429819cf | Tom Hendrikx | echo graph_args --base 1000 |
| 456 | echo graph_vlabel Messages |
||
| 457 | echo graph_total Total |
||
| 458 | echo "graph_info This graph shows the messages that DSPAM processed for $uid ($uid_count uids). Messages are divided in the following categories: true positives/negatives, false positives/negatives, and corpusfed ham/spam." |
||
| 459 | echo tp.label True positives |
||
| 460 | echo tp.info Spam messages correctly classified as spam. |
||
| 461 | echo tp.draw AREASTACK |
||
| 462 | echo tn.label True negatives |
||
| 463 | echo tn.info Ham messages correctly classified as ham. |
||
| 464 | echo tn.draw AREASTACK |
||
| 465 | echo fp.label False positives |
||
| 466 | echo fp.info Ham messages incorrectly classified as spam, but corrected by the user. |
||
| 467 | echo fp.draw AREASTACK |
||
| 468 | echo fn.label False negatives |
||
| 469 | echo fn.info Spam messages incorrectly classified as ham, but corrected by the user. |
||
| 470 | echo fn.draw AREASTACK |
||
| 471 | echo sc.label Corpusfed spam |
||
| 472 | echo sc.info Spam messages from a collected corpus for training purposes. |
||
| 473 | echo sc.draw AREASTACK |
||
| 474 | echo nc.label Corpusfed ham |
||
| 475 | echo nc.info Ham messages from a collected corpus for training purposes. |
||
| 476 | echo nc.draw AREASTACK |
||
| 477 | ;; |
||
| 478 | |||
| 479 | *) |
||
| 480 | debug no config available for graph: $graph, exiting with error |
||
| 481 | exit 78 # EX_CONFIG |
||
| 482 | ;; |
||
| 483 | esac |
||
| 484 | debug finished with printing config for graph: $graph |
||
| 485 | } |
||
| 486 | |||
| 487 | # |
||
| 488 | # print_fetch |
||
| 489 | # Output for 'munin-run <plugin> fetch' command: the actual data to graph. |
||
| 490 | # |
||
| 491 | print_fetch() {
|
||
| 492 | debug printing fetch for graph: $graph |
||
| 493 | |||
| 494 | while file_is_locked $statefile; do |
||
| 495 | debug statefile is locked, waiting |
||
| 496 | sleep 1 |
||
| 497 | done |
||
| 498 | |||
| 499 | case $graph in |
||
| 500 | accuracy) |
||
| 501 | if [ -n "$pattern" ]; then |
||
| 502 | debug env.pattern was set, so use it: $pattern |
||
| 503 | continue |
||
| 504 | 8cf82404 | Tom Hendrikx | elif [ $target = "ALL" ]; then |
| 505 | 429819cf | Tom Hendrikx | local pattern="-v TOTAL" |
| 506 | debug target=ALL: need pattern for all users, but not for TOTAL: $pattern |
||
| 507 | else |
||
| 508 | local pattern="\b$target\b" |
||
| 509 | debug target=$target: need pattern for a single user: $pattern |
||
| 510 | fi |
||
| 511 | |||
| 512 | debug starting grep for user data in statefile |
||
| 513 | local t_start=$(date +%s) |
||
| 514 | grep $pattern $statefile | while read x clean_user x x x x x x x x oca x; do |
||
| 515 | echo $clean_user.value $oca |
||
| 516 | done |
||
| 517 | local t_end=$(date +%s) |
||
| 518 | debug grep finished, runtime $((t_end - t_start)) seconds |
||
| 519 | ;; |
||
| 520 | |||
| 521 | processed) |
||
| 522 | if [ -n "$pattern" ]; then |
||
| 523 | debug env.pattern was set, so use it: $pattern |
||
| 524 | continue |
||
| 525 | elif [ $target = "ALL" ]; then |
||
| 526 | local pattern="TOTAL" |
||
| 527 | debug target=ALL: need pattern for TOTAL of all users: $pattern |
||
| 528 | else |
||
| 529 | local pattern="\b$target\b" |
||
| 530 | debug target=$target: need pattern for a single user: $pattern |
||
| 531 | fi |
||
| 532 | |||
| 533 | local tmpfile=$(mktemp) || debug failed to create tmpfile && debug tmpfile created at: $tmpfile |
||
| 534 | debug starting grep for user data in statefile, sending to tmpfile |
||
| 535 | local t_start=$(date +%s) |
||
| 536 | grep $pattern $statefile > $tmpfile |
||
| 537 | local t_end=$(date +%s) |
||
| 538 | debug grep finished, runtime $((t_end - t_start)) seconds |
||
| 539 | |||
| 540 | debug starting loop over data in tmpfile |
||
| 541 | while read user x tp tn fp fn sc nc x; do |
||
| 542 | debug read data for user $user: $tp $tn $fp $fn $sc $nc |
||
| 543 | all_tp=$((all_tp + tp)) |
||
| 544 | all_tn=$((all_tn + tn)) |
||
| 545 | all_fp=$((all_fp + fp)) |
||
| 546 | all_fn=$((all_fn + fn)) |
||
| 547 | all_sc=$((all_sc + sc)) |
||
| 548 | all_nc=$((all_nc + nc)) |
||
| 549 | debug calculated new totals: $all_tp $all_tn $all_fp $all_fn $all_sc $all_nc |
||
| 550 | done < $tmpfile |
||
| 551 | debug finished data loop |
||
| 552 | rm -f $tmpfile || debug failed to remove tmpfile && debug removed tmpfile |
||
| 553 | |||
| 554 | local total=$((all_tp + all_tn + all_fp + all_fn + all_sc + all_nc)) |
||
| 555 | debug calculated total of all messages: $total |
||
| 556 | echo tp.value $(abs2perc $all_tp $total) |
||
| 557 | echo tn.value $(abs2perc $all_tn $total) |
||
| 558 | echo fp.value $(abs2perc $all_fp $total) |
||
| 559 | echo fn.value $(abs2perc $all_fn $total) |
||
| 560 | echo sc.value $(abs2perc $all_sc $total) |
||
| 561 | echo nc.value $(abs2perc $all_nc $total) |
||
| 562 | ;; |
||
| 563 | |||
| 564 | absprocessed) |
||
| 565 | if [ -n "$pattern" ]; then |
||
| 566 | debug env.pattern was set, so use it: $pattern |
||
| 567 | continue |
||
| 568 | elif [ $target = "ALL" ]; then |
||
| 569 | local pattern="TOTAL" |
||
| 570 | debug target=ALL: need pattern for TOTAL of all users: $pattern |
||
| 571 | else |
||
| 572 | local pattern="\b$target\b" |
||
| 573 | debug target=$target: need pattern for a single user: $pattern |
||
| 574 | fi |
||
| 575 | |||
| 576 | local tmpfile=$(mktemp) || debug failed to create tmpfile && debug tmpfile created at: $tmpfile |
||
| 577 | debug starting grep for user data in statefile, sending to tmpfile |
||
| 578 | local t_start=$(date +%s) |
||
| 579 | grep $pattern $statefile > $tmpfile |
||
| 580 | local t_end=$(date +%s) |
||
| 581 | debug grep finished, runtime $((t_end - t_start)) seconds |
||
| 582 | |||
| 583 | debug starting loop over data in tmpfile |
||
| 584 | while read user x tp tn fp fn sc nc x; do |
||
| 585 | debug read data for user $user: $tp $tn $fp $fn $sc $nc |
||
| 586 | all_tp=$((all_tp + tp)) |
||
| 587 | all_tn=$((all_tn + tn)) |
||
| 588 | all_fp=$((all_fp + fp)) |
||
| 589 | all_fn=$((all_fn + fn)) |
||
| 590 | all_sc=$((all_sc + sc)) |
||
| 591 | all_nc=$((all_nc + nc)) |
||
| 592 | debug calculated new totals: $all_tp $all_tn $all_fp $all_fn $all_sc $all_nc |
||
| 593 | done < $tmpfile |
||
| 594 | debug finished data loop |
||
| 595 | rm -f $tmpfile || debug failed to remove tmpfile && debug removed tmpfile |
||
| 596 | |||
| 597 | echo tp.value $all_tp |
||
| 598 | echo tn.value $all_tn |
||
| 599 | echo fp.value $all_fp |
||
| 600 | echo fn.value $all_fn |
||
| 601 | echo sc.value $all_sc |
||
| 602 | echo nc.value $all_nc |
||
| 603 | ;; |
||
| 604 | |||
| 605 | *) |
||
| 606 | debug no fetch available for graph: $graph, exiting with error |
||
| 607 | exit 78 # EX_CONFIG |
||
| 608 | ;; |
||
| 609 | esac |
||
| 610 | debug finished printing fetch for graph: $graph |
||
| 611 | } |
||
| 612 | |||
| 613 | |||
| 614 | ##################### |
||
| 615 | # Main process loop # |
||
| 616 | ##################### |
||
| 617 | |||
| 618 | # show env settings |
||
| 619 | debug dspam_ plugin started, pid=$$ |
||
| 620 | debug settings: |
||
| 621 | debug - dspam_stats is set to: $dspam_stats |
||
| 622 | debug - statefile is set to: $statefile |
||
| 623 | debug - statefile_max_age is set to: $statefile_max_age |
||
| 624 | debug - warning is set to: $warning |
||
| 625 | debug - critical is set to: $critical |
||
| 626 | debug - pattern is set to: $pattern |
||
| 627 | debug - description is set to: $description |
||
| 628 | |||
| 629 | command=$1 |
||
| 630 | [ -n "$command" ] || command="fetch" |
||
| 631 | debug - command is set to: $command |
||
| 632 | |||
| 633 | graph=$(basename $0 | cut -d'_' -f2) |
||
| 634 | debug - graph is set to: $graph |
||
| 635 | |||
| 636 | target=$(basename $0 | cut -d'_' -f3-) |
||
| 637 | [ -n "$target" ] || target="ALL" |
||
| 638 | debug - target is set to: $target |
||
| 639 | |||
| 640 | debug settings completed, starting process |
||
| 641 | |||
| 642 | case $command in |
||
| 643 | autoconf) |
||
| 644 | print_autoconf |
||
| 645 | ;; |
||
| 646 | suggest) |
||
| 647 | print_suggest |
||
| 648 | ;; |
||
| 649 | config) |
||
| 650 | update_statefile |
||
| 651 | print_config |
||
| 652 | ;; |
||
| 653 | fetch) |
||
| 654 | update_statefile |
||
| 655 | print_fetch |
||
| 656 | ;; |
||
| 657 | esac |
||
| 658 | |||
| 659 | debug exiting |
||
| 660 | exit 0 # EX_OK |
