Hello,

I work on a project consiting of daemon which runs periodically (10 - 300 
seconds) some bits of code (check nginx status, check presence of some 
processes, ...). This daemon runs on our servers. I use log4perl everywhere. 

However sometimes an admin shuts down nginx for a while (0 - few hours) and do 
some maintainance. Nginx code logs errors when HTTP requests fails. Log file 
is then filled with same repeated message(s).

When I browsed through collectd (monitoring of everything) I found 
utils_complain.[ch] which address this problem. It consists of structure which 
is associated with one error message and functions for logging (complaining, 
integrated into its logging system). It looks like this:

// inside collectd plugin, code executed periodically
c_complain(c, ERROR, "connecting failed");

The above logs only if (c->last + c->interval) is less or equal time(). c-
>interval is doubled on every call. c->last is last time of logging.

After success c->interval is set to 0 with:

c_release(c);

This module is a copy of this C code (a bit generalized). Altough it's really 
simple piece of code, I thought it could be useful for other peoples and I 
don't know any other use cases than logging so I'm posting it here (patch 
attached). I'll make better docs ASAP.

Regards,
Thomas.
From 7928be6a0b57581c996fa8a34e3937690327a70b Mon Sep 17 00:00:00 2001
From: Tomas Nechutny <nech...@gmail.com>
Date: Sun, 18 Jul 2010 22:56:59 +0200
Subject: [PATCH] Add Complaint class & test

---
 lib/Log/Log4perl/Util/Complaint.pm |  131 ++++++++++++++++++++++++++++++++++++
 t/061Complaint.t                   |   48 +++++++++++++
 2 files changed, 179 insertions(+), 0 deletions(-)
 create mode 100644 lib/Log/Log4perl/Util/Complaint.pm
 create mode 100644 t/061Complaint.t

diff --git a/lib/Log/Log4perl/Util/Complaint.pm b/lib/Log/Log4perl/Util/Complaint.pm
new file mode 100644
index 0000000..b70929c
--- /dev/null
+++ b/lib/Log/Log4perl/Util/Complaint.pm
@@ -0,0 +1,131 @@
+
+=head1 NAME
+
+Log::Log4perl::Util::Complaint - Do something once or on increasing interval
+
+=head1 SYNOPSIS
+
+    use Log::Log4perl::Util::Complaint;
+
+    my $c = Log::Log4perl::Util::Complaint->new;
+
+    # inside infinite loop
+
+    my $fh = my_connect();
+    unless ($fh) {
+        $log->error("connect(): $!") if $c->take;
+    }
+
+=head1 DESCRIPTION
+
+This module is used for reduction of error log messages when error occurs
+repeatedly in loop. It was inspired by utils_complain from collectd.
+
+=cut
+
+# TODO documentation
+
+package Log::Log4perl::Util::Complaint;
+
+use strict;
+use warnings;
+
+our $FIRST_INTERVAL = 5;
+our $MAX_INTERVAL   = 86400 * 7;
+
+sub new
+{
+    my ( $class, $first_interval, $max_interval ) = @_;
+
+    my $self = {};
+
+    $$self{last}     = 0;
+    $$self{interval} = 0;
+
+    $$self{first_interval} =
+      defined $first_interval ? $first_interval : $FIRST_INTERVAL;
+
+    $$self{max_interval} =
+      defined $max_interval ? $max_interval : $MAX_INTERVAL;
+
+    return bless( $self, $class );
+}
+
+sub take_internal
+{
+    my ($self) = @_;
+
+    my $now = time;
+
+    if ( $$self{last} + $$self{interval} > $now ) {
+        return 0;
+    }
+
+    $$self{last} = $now;
+
+    if ( $$self{interval} < $$self{first_interval} ) {
+        $$self{interval} = $$self{first_interval};
+    }
+    else {
+        $$self{interval} *= 2;
+    }
+
+    if ( $$self{interval} > $$self{max_interval} ) {
+        $$self{interval} = $$self{max_interval};
+    }
+
+    return 1;
+}
+
+sub take
+{
+    my ($self) = @_;
+
+    if ( $$self{interval} < 0 ) {    # reset `once' status
+        $$self{interval} *= -1;
+    }
+
+    return $self->take_internal;
+}
+
+sub take_once
+{
+    my ($self) = @_;
+
+    if ( $$self{interval} < 0 ) {
+        return 0;
+    }
+
+    if ( $self->take_internal ) {
+        $$self{interval} *= -1;
+        return 1;
+    }
+
+    return 0;
+}
+
+sub would_reset
+{
+    my ($self) = @_;
+
+    return $$self{interval} != 0;
+}
+
+sub reset
+{
+    my ($self) = @_;
+
+    $$self{interval} = 0;
+}
+
+1;
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2010 by Tomas Nechutny E<lt>nech...@gmail.come<gt>.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself. 
+
+=cut
+
diff --git a/t/061Complaint.t b/t/061Complaint.t
new file mode 100644
index 0000000..edfdab7
--- /dev/null
+++ b/t/061Complaint.t
@@ -0,0 +1,48 @@
+use strict;
+use warnings;
+
+use Test::More qw(no_plan);
+
+use Log::Log4perl::Util::Complaint;
+
+my $c = Log::Log4perl::Util::Complaint->new( 1, 5 );
+
+ok( $c->take );
+is( $$c{interval}, 1 );
+
+sleep 1;
+
+ok( $c->take );
+is( $$c{interval}, 2 );
+ok( not $c->take );
+
+sleep 2;
+
+ok( $c->take );
+is( $$c{interval}, 4 );
+ok( not $c->take );
+
+sleep 4;
+
+ok( $c->take );
+is( $$c{interval}, 5 );
+ok( not $c->take );
+
+sleep 5;
+
+ok( $c->take );
+is( $$c{interval}, 5 );
+ok( not $c->take );
+
+sleep 5;
+
+ok( $c->take_once );
+is( $$c{interval}, -5 );
+ok( not $c->take_once );
+
+ok( $c->would_reset );
+
+$c->reset;
+is( $$c{interval}, 0 );
+ok( $c->take );
+
-- 
1.7.1

------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
log4perl-devel mailing list
log4perl-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/log4perl-devel

Reply via email to