From 5d53ee2c5ab43777bf41749e2b89e3dc72ac1473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 20 Aug 2024 07:27:19 +0200 Subject: [PATCH] NixLog: avoid spawning tail and sh by tailing directly In the common case we just read 50 lines so it seems wasteful to shell out. Also makes the decompression code a bit more readable. --- src/lib/Hydra/View/NixLog.pm | 46 ++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/lib/Hydra/View/NixLog.pm b/src/lib/Hydra/View/NixLog.pm index fe37d9001..8c84bed6c 100644 --- a/src/lib/Hydra/View/NixLog.pm +++ b/src/lib/Hydra/View/NixLog.pm @@ -5,6 +5,26 @@ use warnings; use base qw/Catalyst::View/; use Hydra::Helper::CatalystUtils; +sub tail { + my ($filehandle, $n) = @_; + my @lines; + my $line_count = 0; + + while (my $line = <$filehandle>) { + $lines[$line_count % $n] = $line; + $line_count++; + } + + my $start = $line_count > $n ? $line_count % $n : 0; + my $end = $line_count > $n ? $n : $line_count; + + my $result = ""; + for my $i (0 .. $end - 1) { + $result .= $lines[($start + $i) % $n]; + } + return $result; +} + sub process { my ($self, $c) = @_; @@ -12,28 +32,28 @@ sub process { $c->response->content_type('text/plain; charset=utf-8'); - my $fh = IO::Handle->new(); + my $logFh = IO::Handle->new(); - my $tail = int($c->stash->{tail} // "0"); + my $tailLines = int($c->stash->{tail} // "0"); if ($logPath =~ /\.zst$/) { - my $doTail = $tail ? "| tail -n '$tail'" : ""; - open($fh, "-|", "zstd -dc < '$logPath' $doTail") or die; + open($logFh, "-|", "zstd", "-dc", $logPath) or die; } elsif ($logPath =~ /\.bz2$/) { - my $doTail = $tail ? "| tail -n '$tail'" : ""; - open($fh, "-|", "bzip2 -dc < '$logPath' $doTail") or die; + open($logFh, "-|", "bzip2", "-dc", $logPath) or die; } else { - if ($tail) { - open($fh, "-|", "tail -n '$tail' '$logPath'") or die; - } else { - open($fh, "<", $logPath) or die; - } + open($logFh, "<", $logPath) or die; } - binmode($fh); setCacheHeaders($c, 365 * 24 * 60 * 60) if $c->stash->{finished}; - $c->response->body($fh); + if ($tailLines > 0) { + my $logEnd = tail($logFh, $tailLines); + $c->response->body($logEnd); + return 1; + } + + binmode($logFh); + $c->response->body($logFh); return 1; }