Blame scripts/services/postgresql

Packit 57988d
##########################################################################
Packit 57988d
# $Id$
Packit 57988d
##########################################################################
Packit 57988d
#
Packit 57988d
# Logwatch service for postgresql error log
Packit 57988d
#
Packit 57988d
# Processes all messages and summarizes them
Packit 57988d
# Each message is given with a timestamp and RMS
Packit 57988d
#
Packit 57988d
########################################################
Packit 57988d
# (C) 2011 by Dalibo - http://www.dalibo.com/
Packit 57988d
# written by Gilles Darold.
Packit 57988d
#
Packit 57988d
# Heavily based on the mysql script by Jeremias Reith
Packit 57988d
########################################################
Packit 57988d
## Covered under the included MIT/X-Consortium License:
Packit 57988d
##    http://www.opensource.org/licenses/mit-license.php
Packit 57988d
## All modifications and contributions by other persons to
Packit 57988d
## this script are assumed to have been donated to the
Packit 57988d
## Logwatch project and thus assume the above copyright
Packit 57988d
## and licensing terms.  If you want to make contributions
Packit 57988d
## under your own copyright or a different license this
Packit 57988d
## must be explicitly stated in the contribution and the
Packit 57988d
## Logwatch project reserves the right to not accept such
Packit 57988d
## contributions.  If you have made significant
Packit 57988d
## contributions to this script and want to claim
Packit 57988d
## copyright please contact logwatch-devel@lists.sourceforge.net.
Packit 57988d
########################################################
Packit 57988d
Packit 57988d
use strict;
Packit 57988d
use Logwatch ':dates';
Packit 57988d
use Time::Local;
Packit 57988d
use POSIX qw(strftime);
Packit 57988d
Packit 57988d
# Allow timestamp from two different logfile format: syslog and stderr
Packit 57988d
my $date_format1 = '%Y-%m-%d %H:%M:%S';
Packit 57988d
my $date_format2 = '%b %e %H:%M:%S';
Packit 57988d
my $filter1 = TimeFilter($date_format1);
Packit 57988d
my $filter2 = TimeFilter($date_format2);
Packit 57988d
Packit 57988d
Packit 57988d
# Allow summarization of WARNING and HINT too if wanted
Packit 57988d
my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0;
Packit 57988d
Packit 57988d
# Used to replace the month trigram into the syslog timestamp
Packit 57988d
my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3,
Packit 57988d
		  May => 4, Jun => 5, Jul => 6, Aug => 7,
Packit 57988d
		  Sep => 8, Oct => 9, Nov => 10, Dec => 11 );
Packit 57988d
Packit 57988d
# Array of the relevant lines in the log file.
Packit 57988d
# First element: type of event
Packit 57988d
# Second element: matching regexp ($1 should contain the message)
Packit 57988d
# Third element: anonymous hash ref (stores message counts)
Packit 57988d
my @message_categories = (
Packit 57988d
	['Panics', qr/PANIC: (.*)$/o, {}],
Packit 57988d
	['Fatals', qr/FATAL: (.*)$/o, {}],
Packit 57988d
	['Errors', qr/ERROR: (.*)$/o, {}]
Packit 57988d
);
Packit 57988d
if ($detail) {
Packit 57988d
	# Add more log information
Packit 57988d
	push(@message_categories,
Packit 57988d
		['Warnings', qr/WARNING: (.*)$/o, {}],
Packit 57988d
		['Hints', qr/HINT: (.*)$/o, {}]
Packit 57988d
	);
Packit 57988d
}
Packit 57988d
Packit 57988d
# Set the current year as syslog don't have this information.
Packit 57988d
my $cur_year = (localtime(time))[5];
Packit 57988d
Packit 57988d
# Parse messages from stdin
Packit 57988d
while(<>) {
Packit 57988d
    my $line = $_;
Packit 57988d
    # skipping messages that are not within the requested range
Packit 57988d
    next unless $line =~ /^($filter1|$filter2)/o;
Packit 57988d
    my $datetime = $1;
Packit 57988d
    my $time = '';
Packit 57988d
    # Date/time format differ following the log_destination (stderr or syslog)
Packit 57988d
    if ($datetime =~ /(\d{4})-(\d{2})-(\d{2})\s+(\d+):(\d+):(\d+)/) {
Packit 57988d
	    {
Packit 57988d
		# timelocal is quite chatty
Packit 57988d
		local $SIG{'__WARN__'}  = sub {};
Packit 57988d
Packit 57988d
		$time = timelocal($6, $5, $4, $3, $2-1, $1-1900);
Packit 57988d
	    }
Packit 57988d
    } elsif ($datetime =~ /(\w)\s+(\d+)\s+(\d+):(\d+):(\d+)/) {
Packit 57988d
	    {
Packit 57988d
		# timelocal is quite chatty
Packit 57988d
		local $SIG{'__WARN__'}  = sub {};
Packit 57988d
Packit 57988d
		$time = timelocal($5, $4, $3, $2, $month2num{$1}, $cur_year);
Packit 57988d
	    }
Packit 57988d
    }
Packit 57988d
Packit 57988d
    # Remove character position
Packit 57988d
    $line =~ s/ at character \d+//;
Packit 57988d
Packit 57988d
    foreach my $cur_cat (@message_categories) {
Packit 57988d
	if($line =~ /$cur_cat->[1]/) {
Packit 57988d
	    my $msgs = $cur_cat->[2];
Packit 57988d
	    $msgs->{$1} = {count => '0',
Packit 57988d
			   first_occurrence => $time,
Packit 57988d
			   sum => 0, 
Packit 57988d
			   sqrsum => 0} unless exists $msgs->{$1};
Packit 57988d
	    $msgs->{$1}->{'count'}++;
Packit 57988d
	    # summing up timestamps and squares of timestamps
Packit 57988d
	    # in order to calculate the rms
Packit 57988d
	    # using first occurrence of message as offset in calculation to 
Packit 57988d
	    # prevent an integer overflow
Packit 57988d
	    $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'};
Packit 57988d
	    $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2;
Packit 57988d
	    last;
Packit 57988d
	}
Packit 57988d
    }
Packit 57988d
}
Packit 57988d
Packit 57988d
Packit 57988d
# generating summary
Packit 57988d
foreach my $cur_cat (@message_categories) {
Packit 57988d
    # skipping non-requested message types
Packit 57988d
    next unless keys %{$cur_cat->[2]};
Packit 57988d
    my ($name, undef, $msgs) = @{$cur_cat};
Packit 57988d
    print $name, ":\n";
Packit 57988d
    print '-' x (length($name)+1), "\n";
Packit 57988d
    my $last_count = 0;
Packit 57988d
Packit 57988d
    # sorting messages by count
Packit 57988d
    my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs};
Packit 57988d
Packit 57988d
    foreach my $msg (@sorted_msgs) {
Packit 57988d
	# grouping messages by number of occurrence
Packit 57988d
	print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'};   
Packit 57988d
	my $rms = 0;
Packit 57988d
Packit 57988d
Packit 57988d
	# printing timestamp
Packit 57988d
        print '[';
Packit 57988d
Packit 57988d
	if($msgs->{$msg}->{'count'} > 1) {
Packit 57988d
	    # calculating rms
Packit 57988d
	    $rms = int(sqrt(
Packit 57988d
			   ($msgs->{$msg}->{'count'} * 
Packit 57988d
			    $msgs->{$msg}->{'sqrsum'} - 
Packit 57988d
			    $msgs->{$msg}->{'sum'}) / 
Packit 57988d
			   ($msgs->{$msg}->{'count'} * 
Packit 57988d
			    ($msgs->{$msg}->{'count'} - 1))));
Packit 57988d
Packit 57988d
	    print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2)));
Packit 57988d
Packit 57988d
	    print ' +/-';
Packit 57988d
	    
Packit 57988d
	    # printing rms
Packit 57988d
	    if($rms > 86400) {
Packit 57988d
		print int($rms/86400) , ' day(s)';
Packit 57988d
	    } elsif($rms > 3600) {
Packit 57988d
		print int($rms/3600) , ' hour(s)';
Packit 57988d
	    } elsif($rms > 60) {
Packit 57988d
		print int($rms/60) , ' minute(s)';
Packit 57988d
	    } else {
Packit 57988d
		print $rms, ' seconds';
Packit 57988d
	    }
Packit 57988d
	} else {
Packit 57988d
	    # we have got this message a single time
Packit 57988d
	    print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}));
Packit 57988d
	}
Packit 57988d
	   
Packit 57988d
	print '] ', $msg, "\n";	
Packit 57988d
	$last_count = $msgs->{$msg}->{'count'};
Packit 57988d
    }
Packit 57988d
Packit 57988d
    print "\n";
Packit 57988d
}
Packit 57988d