
########################################################
# Please file all bug reports, patches, and feature
# requests under:
#      https://sourceforge.net/p/logwatch/_list/tickets
# Help requests and discusion can be filed under:
#      https://sourceforge.net/p/logwatch/discussion/
########################################################

########################################################
## Copyright (c) 2014-2019 Orion Poplawski
## Covered under the included MIT/X-Consortium License:
##    http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms.  If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution an the
## Logwatch project reserves the right to not accept such
## contributions.  If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################

use strict;
my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
my %ErrorThreshold;
if (defined($ENV{'error_threshold'})) {
   foreach my $entry (split(',',$ENV{'error_threshold'})) {
      my ($regex,$limit) = split(';',$entry);
      $ErrorThreshold{$regex} = $limit;
   }
}

my %Errors;
my %Warnings;
my %Startup;
my $Stop;
my %BackupStarted;
my $BackupCompleted;
my %BackupFile;
my %Export;
my %NSSCiphers;
my %SSLInit;
my %Info;
my %OtherList;
my $PreviousLine = '';

while (defined(my $ThisLine = <STDIN>)) {
   chomp($ThisLine);
   
   if ($ThisLine =~ /^Listening for new connections again$/
       or $ThisLine =~ /^Beginning export of /
       or $ThisLine =~ /^Export finished/
       or $ThisLine =~ /Listening on .* (for LDAPI requests|port)/
       or $ThisLine =~ /^Waiting for \d+ database threads to stop/
       or $ThisLine =~ /^slapd shutting down - /
       or $ThisLine =~ /^SSL alert: Configured NSS Ciphers$/
       or $ThisLine =~ /^ldbm_back_.* - conn=/
       or $ThisLine =~ /^ldbm_usn_init - backend: /
       # https://pagure.io/389-ds-base/issue/48973
       or $ThisLine =~ /default_mr_indexer_create.*- [Pp]lugin \[caseIgnoreIA5Match\] does not handle caseExactIA5Match/
       or $ThisLine =~ /^WARN - Security Initialization - SSL alert: Sending pin request to SVRCore. You may need to run systemd-tty-ask-password-agent to provide the password/
       # Will not be a warning in future versions
       or $ThisLine =~ /^WARN - content-sync-plugin - sync_update_persist_betxn_pre_op - DB retried operation targets .* => op not changed in PL/
       or $ThisLine =~ /^ERR - NSACLPlugin - acl_parse - The ACL target .* does not exist/
       or $ThisLine =~ /^ERR - cos-plugin - cos_dn_defs_cb - Skipping CoS Definition .*no CoS Templates found, which should be added before the CoS Definition/
      ) {
      #Ignore
   } elsif ($ThisLine =~ /^ERR - /
       or $ThisLine =~ /error/i
       or $ThisLine =~ /^Detected Disorderly Shutdown/) {
      # Remove some items that prevent de-duplication
      $ThisLine =~ s/:\s+\d+\s+\d+//;
      $ThisLine =~ s/change record \d+/change record/;
      $Errors{$ThisLine}++;
   } elsif ($ThisLine =~ /^WARN - /
       or $ThisLine =~ /warning/i
       or $ThisLine =~ /^Not listening for new connections/) {
      $Warnings{$ThisLine}++;
   } elsif ($ThisLine =~ /^(.*) starting up$/) {
      $Startup{$1}++;
   } elsif ($ThisLine =~ /^slapd stopped\.$/) {
      $Stop++;
   } elsif ($ThisLine =~ /^Beginning backup of '(.*)'$/) {
      $BackupStarted{$1}++;
   } elsif ($ThisLine =~ /^Backup finished\.$/) {
      $BackupCompleted++;
   } elsif ($ThisLine =~ /^Backing up file \d+ \((.*)\)$/) {
      $BackupFile{$1}++;
   } elsif ($ThisLine =~ /^Copying (.*) to /) {
      $BackupFile{$1}++;
   } elsif ($ThisLine =~ /^export (\w+: Processed \d+ entries \(\d+%\)\.)$/) {
      $Export{$1}++;
   } elsif ($ThisLine =~ /^SSL alert:\s+(\S+): (\w+)/) {
      $NSSCiphers{$1} = $2;
   } elsif ($ThisLine =~ /^SSL Initialization - (.*)/) {
      $SSLInit{$1}++;
   } elsif ($ThisLine =~ /^(Total entry cache size:.*)/
            or $ThisLine =~ /^(userRoot: entry cache size:.*)/) {
      $Info{$1}++;
   } elsif ($ThisLine =~ /^All database threads now stopped$/) {
      #This line follows the previous normally in backups or shutdown
      $OtherList{$ThisLine}++ unless $PreviousLine =~ /^(export \w+: Processed \d+ entries|Waiting for \d+ database threads to stop|Backing up file|Copying .* to )/;
   } else {
      next if $ThisLine =~ /^INFO -/ and $Detail < 10;
      next if $ThisLine =~ /^NOTICE -/ and $Detail < 5;
      $OtherList{$ThisLine}++;
   }
   $PreviousLine = $ThisLine;
}

if (keys %Errors and keys %ErrorThreshold) {
   LINE: foreach my $line (keys %Errors) {
      foreach my $regex (keys %ErrorThreshold) {
         if ($line =~ /$regex/i and $Errors{$line} <= $ErrorThreshold{$regex}) {
            delete $Errors{$line};
            next LINE;
         }
      }
   }
}

if (keys %Warnings and keys %ErrorThreshold) {
   LINE: foreach my $line (keys %Warnings) {
      foreach my $regex (keys %ErrorThreshold) {
         if ($line =~ /$regex/i and $Warnings{$line} <= $ErrorThreshold{$regex}) {
            delete $Warnings{$line};
            next LINE;
         }
      }
   }
}

if (keys %Errors) {
   print "\n** ERRORS **\n";
   foreach my $line (sort {$a cmp $b} keys %Errors) {
      print "   $line: $Errors{$line} Time(s)\n";
   }
}

if (keys %Warnings) {
   print "\n** Warnings:\n";
   foreach my $line (sort {$a cmp $b} keys %Warnings) {
      print "   $line: $Warnings{$line} Time(s)\n";
   }
}

if (keys %Startup and $Detail >= 5) {
   foreach my $Version (keys %Startup) {
      print "\nStart up version $Version: $Startup{$Version} Time(s)\n";
   }
}

if ($Stop and $Detail) {
   print "\nStopped: $Stop Time(s)\n";
}

if (keys %BackupStarted and $Detail) {
   foreach my $Database (keys %BackupStarted) {
      print "\nBackup started for $Database: $BackupStarted{$Database} Time(s)\n";
   }
}

if (keys %BackupFile and $Detail >= 7) {
   print "\nBacked up files:\n";
   foreach my $File (sort {$a cmp $b} keys %BackupFile) {
      print "    $File: $BackupFile{$File} Time(s)\n";
   }
}

if ($BackupCompleted and $Detail) {
   print "\nBackup completed: $BackupCompleted Time(s)\n";
}

if (keys %Export and $Detail) {
   print "\nExports:\n";
   foreach my $Line (keys %Export) {
      print "  $Line $Export{$Line} Time(s)\n";
   }
}

if (keys %Info and $Detail >= 7) {
   print "\nInformational Messages::\n";
   foreach my $Line (keys %Info) {
      print "  $Line $Info{$Line} Time(s)\n";
   }
}

if (keys %SSLInit and $Detail >= 7) {
   print "\nSSL Initialization:\n";
   foreach my $Message (sort {$a cmp $b} keys %SSLInit) {
      print "    $Message\n";
   }
}

if (keys %NSSCiphers and $Detail >= 7) {
   print "\nNSS Ciphers:\n";
   foreach my $Cipher (sort {$a cmp $b} keys %NSSCiphers) {
      print "    $Cipher: $NSSCiphers{$Cipher}\n";
   }
}

if (keys %OtherList) {
   print "\n**Unmatched Entries**\n";
   foreach my $line (sort {$a cmp $b} keys %OtherList) {
      print "   $line: $OtherList{$line} Time(s)\n";
   }
}

