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