Package: swatch Version: 3.1.1-2 Severity: normal The revised docs on throttle/threshold from bug 292584 don't match the upstream code - but regrettably the upstream re-implementation of threshold doesn't work well anyway.
Like you, I believe the syntax the upstream code is trying to implement is as follows, so that 'threshold' is just an integer limit that the throttle must meet before it triggers: throttle hh:mm:ss,threshold=n,repeat=(yes|no),key=(message|regex|<regex>) with 'n' as a simple count (no longer contains a separate time factor) - this is clear from the code; and presumably with hh:mm:ss being the time for the threshold, as usual for throttle. However the upstream code seems incorrect. Firstly it never applies the time limit if there is a threshold. Second, the code ignores the repeat= option and always behaves as repeat=no; and thirdly, the first message matching after restarting swatch is always acted on regardless of the threshold. I've attached a patch which corrects the code to match the amended Debian doc and fixes the above problems, and further alters the amended docs to fully match the fixed code. I hope you agree with my interpretation of what upstream intended, if not please feel free to re-work it, and thank you for your efforts, Nick Leverton -- System Information: Debian Release: 3.1 APT prefers testing APT policy: (60, 'testing'), (2, 'unstable') Architecture: i386 (i686) Kernel: Linux 2.6.15-1-k7 Locale: LANG=en_GB.ISO-8859-15, LC_CTYPE=en_GB.ISO-8859-15 (charmap=ISO-8859-15)
--- lib/Swatch/Throttle.pm.orig 2004-07-19 21:14:54.000000000 +0100 +++ lib/Swatch/Throttle.pm 2006-05-16 18:12:50.000000000 +0100 @@ -98,7 +98,15 @@ my @dmyhms; my $key; my $cur_rec; - my $msg = $opts{"MESSAGE"}; + my $ret = ""; + + my $threshold = (exists $opts{THRESHOLD} ? $opts{THRESHOLD} : 1); + my $repeat; + if (exists $opts{REPEAT}) { + $repeat = ( $opts{REPEAT} =~ /^yes$/i ); # was repeat= specified ? if so remember it. + } else { + $repeat = ( exists $opts{THRESHOLD} ); # default=yes if we have a threshold, else no + } ## get the time ## if ($opts{TIME_FROM} eq 'realtime') { @@ -128,37 +136,46 @@ } ## just make the record if it doesn't exist yet ## - if (not defined $LogRecords{$key}) { - my $rec = (); - $rec->{KEY} = $key; - $rec->{FIRST} = [ @dmyhms ]; - $rec->{LAST} = [ @dmyhms ]; - $rec->{HOLD_DHMS} = $opts{HOLD_DHMS} if defined $opts{HOLD_DHMS}; - $rec->{COUNT} = 1; - $LogRecords{$key} = $rec; - return $msg; - } else { + if (defined $LogRecords{$key}) { $cur_rec = $LogRecords{$key}; $cur_rec->{COUNT}++; - if (defined $opts{THRESHOLD} and $cur_rec->{COUNT} == $opts{THRESHOLD}) { - ## threshold exceeded ## - chomp $msg; - $msg = "$msg (threshold $opts{THRESHOLD} exceeded)"; - $cur_rec->{COUNT} = 0; - } elsif (defined $opts{HOLD_DHMS} - and past_hold_time($cur_rec->{LAST}, - [EMAIL PROTECTED], $opts{HOLD_DHMS})) { + $cur_rec->{UNPRINTED}++; + } else { + $cur_rec = (); + $cur_rec->{KEY} = $key; + $cur_rec->{FIRST} = [ @dmyhms ]; + $cur_rec->{LAST} = [ @dmyhms ]; # time of start of throttle period + $cur_rec->{HOLD_DHMS} = $opts{HOLD_DHMS} if exists $opts{HOLD_DHMS}; + $cur_rec->{COUNT} = 1; # count seen in this throttle period + $cur_rec->{UNPRINTED} = 1; # count seen since last message printed + } + + # were we throttling and has the throttle period finished ? + if (exists $opts{HOLD_DHMS} + && past_hold_time($cur_rec->{LAST}, [EMAIL PROTECTED], $opts{HOLD_DHMS})) { ## hold time exceeded ## - chomp $msg; - $msg = "$msg (seen $cur_rec->{COUNT} times)"; + $cur_rec->{COUNT} = 1; + $cur_rec->{LAST} = [ @dmyhms ]; + } + + # have we reached the threshold for this throttle period ? + if ($cur_rec->{COUNT} == $threshold) { + ## threshold exceeded, print it out ## + $ret = $opts{"MESSAGE"}; + chomp $ret; + # $ret = "$ret (threshold $opts{THRESHOLD} exceeded)" if exists $opts{THRESHOLD}; + $ret = "$ret (seen $cur_rec->{UNPRINTED} times)" if $cur_rec->{UNPRINTED} > 1; + $cur_rec->{UNPRINTED} = 0; + # do we want repeated messages after reaching the threshold ? + if ($repeat) { + # no, start a new throttle period $cur_rec->{COUNT} = 0; $cur_rec->{LAST} = [ @dmyhms ]; - } else { - $msg = ''; } - $LogRecords{$key} = $cur_rec if exists($LogRecords{$key}); ## save any new values ## } - return $msg; + + $LogRecords{$key} = $cur_rec; ## save any new values ## + return $ret; } ################################################################ --- swatch.orig 2006-05-16 13:03:06.000000000 +0100 +++ swatch 2006-05-16 17:18:01.000000000 +0100 @@ -197,36 +197,39 @@ Use B<write(1)> to send matched lines to I<user(s)>. -=item B<throttle hours:minutes:seconds,[use=message|regex|<regex>]> +=item B<throttle [days:[hours:]]minutes:seconds [,option ...] Use this action to limit the number of times that the matched pattern has actions performed on it. -The B<use=regex> option will cause throttling to be based on the regular -expression instead of the message. - -You can also specify a perl compliant regular expression as the value for B,use>. The default is use="^\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}\s+(.*)" causes the key to be the syslog message without the timestamp. This is most useful when throttling non-syslog created files. +=over -=item B<threshold events:seconds,[repeat=no|yes]> +B<use=regex> option will cause throttling to be based on the regular +expression instead of the message. -This action limits the actions on a matched pattern based on the number of -times it appears in a given time frame. An action like "threshold 4:60" -will not perform any actions on that pattern unless it appears 4 times -within any 60 second period (4:60 is the arbitrary default value). +You can also specify a perl compliant regular expression as the value for +B<use=>. The default is use="^\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}\s+(.*)" +causes the key to be the syslog message without the timestamp. This is +most useful when throttling non-syslog created files. + +B<threshold=events> further limits the throttling on a matched +pattern so that it will not be acted on until the specified number of +events have been matched in the throttle time frame. An action like +"throttle 0:0:60,threshold=4" will not perform any actions on that +pattern unless it appears 4 times within 60 seconds. -The B<repeat=no> option will prevent the timer from being reset after the +B<repeat=no> will prevent the timer from being reset after the threshold has been reached. By default (repeat=yes), once the pattern has -been triggered, a new 60 second period is begun, which means that if the -patterns match quickly enough, a threshold of 4:60 could mean that 1 in -every 4 messages is reported. By using B<repeat=no>, you indicate that -there is not to be more than one match every time interval. - -Note that this is similar to, but different from, the standard "throttle" -command, since "throttle" shows the first line and ignores the rest, while -"threshold" shows the last line and ignores the preceeding (and optionally -the following). However, an action like "threshold 1:120" should perform -similarly to "throttle 0:2:0,use=regex" and has the advantage of not relying -on a particular timestamp format in the source log entry. +been triggered, a new period is begun, which means that if the patterns +match quickly enough, a threshold of 4 events in 60 seconds could mean +that 1 in every 4 messages is reported. By using B<repeat=no>, you +indicate that there is not to be more than one match every time interval. + +Thus "throttle" shows the first line and ignores the rest, while +"throttle threshold=N" shows line N and ignores the preceeding (and +optionally the following). + +=back =item B<continue> @@ -242,7 +245,7 @@ =head1 SPECIAL OPTION -The following may be used as an option for any of the above actions except for throttle and threshold. +The following may be used as an option for any of the above actions except for throttle. =over 4