######################################################## # 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) 2013 Teemu Ikonen ## Copyright (c) 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 %IgnoreActions; if (defined($ENV{'rsyslogd_ignore_actions'})) { foreach my $action (split(";",$ENV{'rsyslogd_ignore_actions'})) { $IgnoreActions{$action} = 1; } } my %IgnoreMessages; if (defined($ENV{'rsyslogd_ignore_messages'})) { foreach my $message (split(";",$ENV{'rsyslogd_ignore_messages'})) { $IgnoreMessages{$message} = 1; } } my %IgnoreModules; if (defined($ENV{'rsyslogd_ignore_modules'})) { foreach my $module (split(";",$ENV{'rsyslogd_ignore_modules'})) { $IgnoreModules{$module} = 1; } } my $RemoteClosedThreshold = $ENV{'rsyslogd_remote_closed_threshold'} || 0; #Init String Containers my $Action; my $Certificate; my $Host; my $LastError; my $Message; my $MessagesLost = 0; my $Module; my $Num; my $Reason; #Init Hashes my %ActionResumed; my %ActionSuspended; my %CannotConnect; my %ClosedError; my %DaemonActions; my %InvalidCertificate; my %InvalidCerts; my %OtherList; my %RemoteClosed; LINE: while (defined(my $ThisLine = )) { chomp($ThisLine); foreach $Message (keys %IgnoreMessages) { next LINE if $ThisLine =~ /$Message/i; } if (($Reason) = ($ThisLine =~ /^ ?\[origin software=\"rsyslogd\" .*\] (.*)/)) { $DaemonActions{$Reason}++; } elsif (($Action, $Module) = $ThisLine =~ /action '(.*)' suspended(?: \(module '(.*)'\))?/) { if (defined $Module) { $ActionSuspended{"$Action ($Module)"}++ unless defined $IgnoreActions{$Action} or defined $IgnoreModules{$Module}; } else { $ActionSuspended{$Action}++ unless defined $IgnoreActions{$Action}; } } elsif (($Action, $Module) = $ThisLine =~ /action '(.*)' resumed \(module '(.*)'\)/) { $ActionResumed{"$Action ($Module)"}++ unless defined $IgnoreActions{$Action} or defined $IgnoreModules{$Module}; } elsif (($Certificate) = $ThisLine =~ /invalid cert info: peer provided \d+ certificate\(s\)\. Certificate \d+ info: (.*); \[/) { $InvalidCertificate{$Certificate}++; } elsif (($Host, $Reason) = $ThisLine =~ /cannot connect to (.+): (.+) \[/) { $CannotConnect{"$Host ($Reason)"}++; } # These should also generate closed connection messages, but record so we can ignore normal events elsif( $ThisLine =~ /(TCPSendBuf error .*), destruct TCP Connection to/ or $ThisLine =~ /(GnuTLS handshake retry returned error:[^.]*)/ or # This proceeds unexpected GnuTLS error -54 $ThisLine =~ /(gnutls returned error on handshake:[^.]*)/ or $ThisLine =~ /(peer did not provide a certificate[^[]*)/ or $ThisLine =~ /(unexpected GnuTLS error -\d+)/ ) { $LastError = $1; } elsif (($Host) = $ThisLine =~ /^netstream session \S+ from (\S+) will be closed due to error/) { $ClosedError{$LastError}{"$Host"}++ if $LastError !~ /unexpected GnuTLS error -54/; } elsif (($Host) = $ThisLine =~ /^omfwd: remote server at (.+) seems to have closed connection/) { $RemoteClosed{"$Host"}++; } elsif (($Num) = $ThisLine =~ /(\d+) messages lost due to rate-limiting/) { $MessagesLost += $Num; } elsif ( # More detail for this in the invalid cert info line above $ThisLine =~ /^not permitted to talk to peer, certificate invalid:/ or $ThisLine =~ /^rsyslogd\'s (groupid|userid) changed to/ or $ThisLine =~ /^imjournal: journal files changed, reloading/ or $ThisLine =~ /^imjournal: journal reloaded/ or $ThisLine =~ /^imuxsock: Acquired UNIX socket .* from systemd/ or $ThisLine =~ /^message repeated \d+ times:/ or $ThisLine =~ m!^imuxsock: Acquired UNIX socket '/run/systemd/journal/syslog' \(fd 3\) from systemd! or 0 # This line prevents blame shifting as lines are added above ) { # Ignore these lines } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } if (keys %ActionSuspended) { print "Rsyslogd actions suspended:\n"; foreach my $Action (sort keys %ActionSuspended) { print " $Action: $ActionSuspended{$Action} Times\n"; } print "\n"; } if (keys %ActionResumed) { print "Rsyslogd actions resumed\n"; foreach my $Action (sort keys %ActionResumed) { print " $Action: $ActionResumed{$Action} Times\n"; } print "\n"; } if (keys %CannotConnect) { print "Cannot connect:\n"; foreach my $Item (sort keys %CannotConnect) { print " $Item: $CannotConnect{$Item} Times\n"; } print "\n"; } if (keys %InvalidCertificate) { print "Invalid certificates:\n"; foreach my $Certificate (sort keys %InvalidCertificate) { print " $Certificate: $InvalidCertificate{$Certificate} Times\n"; } print "\n"; } if ($MessagesLost) { print "$MessagesLost Messages lost due to rate-limiting\n\n"; } if (keys %ClosedError) { print "Connection closed due to error:\n"; foreach my $Error (sort keys %ClosedError) { print " $Error:\n"; foreach my $Host (sort keys %{$ClosedError{$Error}}) { print " $Host: $ClosedError{$Error}{$Host} Times\n"; } } print "\n"; } if (keys %RemoteClosed) { my $first = 1; foreach my $Host (sort keys %RemoteClosed) { if ($RemoteClosed{$Host} >= $RemoteClosedThreshold) { if ($first) { print "Remote closed connection:"; print " (with threshold >= $RemoteClosedThreshold)" if $RemoteClosedThreshold; print "\n"; $first = 0; } print " $Host: $RemoteClosed{$Host} Times\n"; } } print "\n"; } if (($Detail >=10) and (keys %DaemonActions) ) { print "Rsyslogd Actions:\n"; foreach $Reason (sort keys %DaemonActions) { print " $Reason: $DaemonActions{$Reason} Times\n"; } print "\n"; } if (keys %OtherList) { print "**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Times\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: