[pve-devel] [RFC common 1/1] tools: Add specialized `dump_fw_logfile` for `since` and `until` filtering of firewall logs

Christian Ebner c.ebner at proxmox.com
Thu Jan 5 10:18:04 CET 2023


This furhter includes the contents of rotated logfiles if present. All files are scanned in
sequential order, as there is no guarantee that the rotated logs contain only entries for
a single day.

Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
 src/PVE/Tools.pm | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index cdbee6d..fdbf0e1 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use Date::Format qw(time2str);
+use Date::Parse qw(str2time);
 use Digest::MD5;
 use Digest::SHA;
 use Encode;
@@ -17,6 +18,7 @@ use IO::Handle;
 use IO::Pipe;
 use IO::Select;
 use IO::Socket::IP;
+use IO::Zlib;
 use IPC::Open3;
 use JSON;
 use POSIX qw(EINTR EEXIST EOPNOTSUPP);
@@ -1320,6 +1322,84 @@ sub dump_logfile {
     return ($count, $lines);
 }
 
+sub dump_fw_logfile {
+    my ($filename, $start, $limit, $filter, $since, $until) = @_;
+
+    if (!(defined($since) || defined($until))) {
+	# Use previous version without `since` and `until` parameters
+	return dump_logfile($filename, $start, $limit, $filter);
+    }
+
+    my $lines = [];
+    my $count = 0;
+
+    # Take into consideration also rotated logs                                              
+    my ($basename, $logdir, $type) = fileparse($filename);
+    my @files = ();                                                                          
+
+    opendir(LOGDIR, $logdir) || die "Cannot open $logdir";
+    my $entry;
+    while ($entry = readdir(LOGDIR)) {
+	my $namefilter = $basename."*";
+	next if $entry !~ m/$namefilter/;
+	push @files, $entry;
+    }
+    closedir(LOGDIR);
+    @files = reverse sort @files;
+    print @files,"\n";
+
+    $start = $start // 0;
+    $limit = $limit // 50;
+
+    my $read_until_end = $limit == 0;
+    my $line;
+    my $fh;
+
+    foreach (@files) {
+	my ($base, $path, $type) = fileparse($_, ".gz");
+
+	if ($type eq '.gz') {
+	    $fh = IO::Zlib->new($logdir.$_, "r");
+	} else {
+	    $fh = IO::File->new($logdir.$_, "r");
+	}
+
+	if (!$fh) {
+	    $count++;
+	    push @$lines, { n => $count, t => "unable to open file - $!"};
+	    return ($count, $lines);
+	}
+
+	while (defined($line = <$fh>)) {
+	    next if defined($filter) && $line !~ m/$filter/;
+	    if ($since || $until) {
+		my @words = split / /, $line;
+		my $timestamp = str2time($words[3], $words[4]);
+		next if $since && $timestamp < $since;
+		next if $until && $timestamp > $until;
+	    }
+	    next if $count++ < $start;
+	    if (!$read_until_end) {
+		next if $limit <= 0;
+		$limit--;
+	    }
+	    chomp $line;
+	    push @$lines, { n => $count, t => $line};
+	}
+
+	close($fh);
+    }
+
+    # HACK: ExtJS store.guaranteeRange() does not like empty array
+    # so we add a line
+    if (!$count) {
+	$count++;
+	push @$lines, { n => $count, t => "no content"};
+    }
+
+    return ($count, $lines);
+}
+
 sub dump_journal {
     my ($start, $limit, $since, $until, $service) = @_;
 
-- 
2.30.2






More information about the pve-devel mailing list