#-*- perl -*- # # Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi # All rights reserved. This program is free software; you can # redistribute it and/or modify it under the same terms as Perl itself. # # $FML: histgram.pm,v 1.15 2006/02/15 13:44:04 fukachan Exp $ # package FML::Error::Analyze::histgram; use strict; use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); use Carp; my $debug = 1; =head1 NAME FML::Error::Analyze::histgram - cost evaluator. =head1 SYNOPSIS my $analyzer = new FML::Error::Analyze::histgram; $analyzer->process($curproc, $data); =head1 DESCRIPTION This class provides analysis based on the histgram model. It examines the continuity of error messages (*). --------------------> time * ok ********* bad * * *** * ambiguous but sum up counts by the delta. * *** =head1 METHODS =head2 new($curproc) constructor. =head2 process($curproc, $data) dispatch analysis. =cut # Descriptions: constructor. # Arguments: OBJ($self) OBJ($curproc) # Side Effects: none # Return Value: OBJ sub new { my ($self, $curproc) = @_; my ($type) = ref($self) || $self; my $me = { _curproc => $curproc }; return bless $me, $type; } # Descriptions: top level dipatcher to run cost evaluator. # Arguments: OBJ($self) OBJ($curproc) HASH_REF($data) # Side Effects: none # Return Value: none sub process { my ($self, $curproc, $data) = @_; $self->_histgram($curproc, $data); } # Descriptions: error continuity based cost counting. # Arguments: OBJ($self) OBJ($curproc) HASH_REF($data) # Side Effects: none # Return Value: none sub _histgram { my ($self, $curproc, $data) = @_; my ($addr, $bufarray, $count, $i, $time, $status, $reason); my @removelist = (); my $summary = {}; my $config = $curproc->config(); my $limit = $config->{ error_mail_analyzer_simple_count_limit } || 14; my $howold = $config->{ error_mail_analyzer_day_limit } || 14; my $now = time; # unix time (seconds). my $half_day = 12 * 3600 ; # 12 hours (seconds). my $one_day = 24 * 3600 ; # 24 hours (seconds). my $threshold = $one_day * $howold; # how old (seconds). # $data format = { # key1 => [ value1, value2, ... ], # key2 => [ value1, value2, ... ], # } while (($addr, $bufarray) = each %$data) { $count = 0; if (defined $bufarray) { BUF: for my $buf (@$bufarray) { ($time, $status, $reason) = split(/\s+/, $buf); # ignore too old data. next BUF if (($now - $time) > $threshold); if ($buf =~ /status=5/i) { unless (defined $summary->{ $addr }) { $summary->{ $addr } = [ 0 ]; } # center of distribution function $i = int( ($now - $time ) / $one_day ); $summary->{ $addr }->[ $i ] += 2; # +delta $i = int( ($now - $time + $half_day) / $one_day ); $summary->{ $addr }->[ $i ] += 1; # -delta $i = int( ($now - $time - $half_day) / $one_day ); $summary->{ $addr }->[ $i ] += 1 if $i >= 0; } elsif ($buf =~ /status=4/i) { unless (defined $summary->{ $addr }) { $summary->{ $addr } = [ 0 ]; } # center of distribution function $i = int( ($now - $time ) / $one_day ); $summary->{ $addr }->[ $i ] += 0.25; # +delta $i = int( ($now - $time + $half_day) / $one_day ); $summary->{ $addr }->[ $i ] += 0.25; # -delta $i = int( ($now - $time - $half_day) / $one_day ); $summary->{ $addr }->[ $i ] += 0.25 if $i >= 0; } } } } # debug info { my $addr = ''; my $ra = (); my $sum = 0; while (($addr, $ra) = each %$summary) { $sum = 0; for my $v (@$ra) { # count if the top of the mountain is over 2. if (defined $v) { $sum += 1 if $v >= 2; } } my $array = _ra_to_str($ra); $curproc->logdebug("summary: $addr sum=$sum ($array)"); push(@removelist, $addr) if $sum >= $limit; } } # save info $self->{ _summary } = $summary; # save address for removal candidates $self->{ _address_to_be_removed } = \@removelist; } # Descriptions: return array list with 0 padding (debug). # Arguments: ARRAY_REF($ra) # Side Effects: none # Return Value: STR sub _ra_to_str { my ($ra) = @_; my $s = ''; for my $x (@$ra) { $s .= defined $x ? $x : 0; $s .= " "; } return $s; } # Descriptions: return summary as HASH_REF. # Arguments: OBJ($self) # Side Effects: none # Return Value: HASH_REF sub get_summary { my ($self) = @_; return( $self->{ _summary } || {} ); } # Descriptions: return addresses to be removed. # Arguments: OBJ($self) # Side Effects: none # Return Value: ARRAY_REF sub get_address_to_be_deleted { my ($self) = @_; return( $self->{ _address_to_be_removed } || [] ); } # Descriptions: print summary for the specified address. # Arguments: OBJ($self) STR($addr) # Side Effects: none # Return Value: none sub print { my ($self, $addr) = @_; my $wh = \*STDOUT; my $summary = $self->get_summary(); my $bufarray = $summary->{ $addr } || []; my $result = _ra_to_str($bufarray); printf $wh "%25s => (%s)\n", $addr, $result; } =head1 CODING STYLE See C on fml coding style guide. =head1 AUTHOR Ken'ichi Fukamachi =head1 COPYRIGHT Copyright (C) 2003,2004,2005,2006 Ken'ichi Fukamachi All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 HISTORY FML::Error::Analyze::simple_count appeared in fml8 mailing list driver package. See C for more details. =cut 1;