[3/3] Add Zabbix Agent Logs viewer in WebGUI

Message ID 20230402110711.19593-4-robin.roevens@disroot.org
State Superseded
Headers
Series [1/3] zabbix_agentd: Update to 6.0.15 (LTS) |

Commit Message

Robin Roevens April 2, 2023, 11:07 a.m. UTC
  - Adds a simple logs viewer page logs.cgi/zabbix_agentd.dat, based
  on logs.cgi/logs.dat, to the Logs menu in GUI.
- Changes permission of zabbix_agentd logfiles in logrotate config
  for GUI to be able to access the log files (640 to 644)
- Changes file permissions of existing zabbix_agentd logfiles upon
  update of the package
- Rootfile changes: added gui page, menu item-file, and addon
  language files
- configroot rootfile changes: added logs menu item-file as comment
- web-user-interface rootfile changes: added log viewer .dat as comment
- Update language cache during install/uninstall

Signed-off-by: Robin Roevens <robin.roevens@disroot.org>
---
 config/menu/EX-zabbix_agentd.menu          |   5 +
 config/rootfiles/common/configroot         |   1 +
 config/rootfiles/common/web-user-interface |   1 +
 config/rootfiles/packages/zabbix_agentd    |   6 +
 config/zabbix_agentd/logrotate             |   2 +-
 config/zabbix_agentd/zabbix_agentd.de.pl   |   8 +
 config/zabbix_agentd/zabbix_agentd.en.pl   |   8 +
 config/zabbix_agentd/zabbix_agentd.fr.pl   |   8 +
 config/zabbix_agentd/zabbix_agentd.nl.pl   |   8 +
 html/cgi-bin/logs.cgi/zabbix_agentd.dat    | 341 +++++++++++++++++++++
 lfs/zabbix_agentd                          |   4 +
 src/paks/zabbix_agentd/install.sh          |   1 +
 src/paks/zabbix_agentd/uninstall.sh        |   1 +
 src/paks/zabbix_agentd/update.sh           |   3 +
 14 files changed, 396 insertions(+), 1 deletion(-)
 create mode 100644 config/menu/EX-zabbix_agentd.menu
 create mode 100644 config/zabbix_agentd/zabbix_agentd.de.pl
 create mode 100644 config/zabbix_agentd/zabbix_agentd.en.pl
 create mode 100644 config/zabbix_agentd/zabbix_agentd.fr.pl
 create mode 100644 config/zabbix_agentd/zabbix_agentd.nl.pl
 create mode 100644 html/cgi-bin/logs.cgi/zabbix_agentd.dat
  

Comments

Michael Tremer April 11, 2023, 12:48 p.m. UTC | #1
Hello Robin,

Thanks for the patch.

> On 2 Apr 2023, at 12:07, Robin Roevens <robin.roevens@disroot.org> wrote:
> 
> - Adds a simple logs viewer page logs.cgi/zabbix_agentd.dat, based
>  on logs.cgi/logs.dat, to the Logs menu in GUI.

Why is an extra CGI script needed? Could not this not be integrated into logs.dat?

-Michael

> - Changes permission of zabbix_agentd logfiles in logrotate config
>  for GUI to be able to access the log files (640 to 644)
> - Changes file permissions of existing zabbix_agentd logfiles upon
>  update of the package
> - Rootfile changes: added gui page, menu item-file, and addon
>  language files
> - configroot rootfile changes: added logs menu item-file as comment
> - web-user-interface rootfile changes: added log viewer .dat as comment
> - Update language cache during install/uninstall
> 
> Signed-off-by: Robin Roevens <robin.roevens@disroot.org>
> ---
> config/menu/EX-zabbix_agentd.menu          |   5 +
> config/rootfiles/common/configroot         |   1 +
> config/rootfiles/common/web-user-interface |   1 +
> config/rootfiles/packages/zabbix_agentd    |   6 +
> config/zabbix_agentd/logrotate             |   2 +-
> config/zabbix_agentd/zabbix_agentd.de.pl   |   8 +
> config/zabbix_agentd/zabbix_agentd.en.pl   |   8 +
> config/zabbix_agentd/zabbix_agentd.fr.pl   |   8 +
> config/zabbix_agentd/zabbix_agentd.nl.pl   |   8 +
> html/cgi-bin/logs.cgi/zabbix_agentd.dat    | 341 +++++++++++++++++++++
> lfs/zabbix_agentd                          |   4 +
> src/paks/zabbix_agentd/install.sh          |   1 +
> src/paks/zabbix_agentd/uninstall.sh        |   1 +
> src/paks/zabbix_agentd/update.sh           |   3 +
> 14 files changed, 396 insertions(+), 1 deletion(-)
> create mode 100644 config/menu/EX-zabbix_agentd.menu
> create mode 100644 config/zabbix_agentd/zabbix_agentd.de.pl
> create mode 100644 config/zabbix_agentd/zabbix_agentd.en.pl
> create mode 100644 config/zabbix_agentd/zabbix_agentd.fr.pl
> create mode 100644 config/zabbix_agentd/zabbix_agentd.nl.pl
> create mode 100644 html/cgi-bin/logs.cgi/zabbix_agentd.dat
> 
> diff --git a/config/menu/EX-zabbix_agentd.menu b/config/menu/EX-zabbix_agentd.menu
> new file mode 100644
> index 000000000..dddd7f05e
> --- /dev/null
> +++ b/config/menu/EX-zabbix_agentd.menu
> @@ -0,0 +1,5 @@
> + $sublogs->{'95.zabbixagent'} = {'caption' => $Lang::tr{'zabbix agent logs'},
> + 'uri' => '/cgi-bin/logs.cgi/zabbix_agentd.dat',
> + 'title' => "$Lang::tr{'zabbix agent logs'}",
> + 'enabled' => 1
> + };
> diff --git a/config/rootfiles/common/configroot b/config/rootfiles/common/configroot
> index bc979cf2c..f12e2e0f0 100644
> --- a/config/rootfiles/common/configroot
> +++ b/config/rootfiles/common/configroot
> @@ -126,6 +126,7 @@ var/ipfire/menu.d/70-log.menu
> #var/ipfire/menu.d/EX-samba.menu
> #var/ipfire/menu.d/EX-tor.menu
> #var/ipfire/menu.d/EX-wlanap.menu
> +#var/ipfire/menu.d/EX-zabbix_agentd.menu
> var/ipfire/modem
> var/ipfire/modem-lib.pl
> #var/ipfire/modem/defaults
> diff --git a/config/rootfiles/common/web-user-interface b/config/rootfiles/common/web-user-interface
> index 33f0d30a7..bc17b4ce4 100644
> --- a/config/rootfiles/common/web-user-interface
> +++ b/config/rootfiles/common/web-user-interface
> @@ -49,6 +49,7 @@ srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromip.dat
> srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromport.dat
> srv/web/ipfire/cgi-bin/logs.cgi/summary.dat
> srv/web/ipfire/cgi-bin/logs.cgi/urlfilter.dat
> +#srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
> srv/web/ipfire/cgi-bin/mac.cgi
> srv/web/ipfire/cgi-bin/mail.cgi
> srv/web/ipfire/cgi-bin/mdstat.cgi
> diff --git a/config/rootfiles/packages/zabbix_agentd b/config/rootfiles/packages/zabbix_agentd
> index 6f2c831d7..5b57026f5 100644
> --- a/config/rootfiles/packages/zabbix_agentd
> +++ b/config/rootfiles/packages/zabbix_agentd
> @@ -7,6 +7,7 @@ etc/zabbix_agentd/scripts
> etc/zabbix_agentd/zabbix_agentd.conf
> etc/zabbix_agentd/zabbix_agentd.conf.example
> etc/zabbix_agentd/zabbix_agentd.d
> +srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
> usr/bin/zabbix_get
> usr/bin/zabbix_sender
> #usr/lib/modules
> @@ -16,6 +17,11 @@ usr/sbin/zabbix_agentd
> #usr/share/man/man1/zabbix_sender.1
> #usr/share/man/man8/zabbix_agentd.8
> var/ipfire/backup/addons/includes/zabbix_agentd
> +var/ipfire/addon-lang/zabbix_agentd.de.pl
> +var/ipfire/addon-lang/zabbix_agentd.en.pl
> +var/ipfire/addon-lang/zabbix_agentd.fr.pl
> +var/ipfire/addon-lang/zabbix_agentd.nl.pl
> +var/ipfire/menu.d/EX-zabbix_agentd.menu
> var/ipfire/zabbix_agentd
> var/ipfire/zabbix_agentd/zabbix_agentd_ipfire_mandatory.conf
> var/ipfire/zabbix_agentd/userparameters
> diff --git a/config/zabbix_agentd/logrotate b/config/zabbix_agentd/logrotate
> index 83bbca9fb..46fee44f2 100644
> --- a/config/zabbix_agentd/logrotate
> +++ b/config/zabbix_agentd/logrotate
> @@ -5,5 +5,5 @@
>     delaycompress
>     missingok
>     notifempty
> -    create 0640 zabbix zabbix
> +    create 0644 zabbix zabbix
> }
> diff --git a/config/zabbix_agentd/zabbix_agentd.de.pl b/config/zabbix_agentd/zabbix_agentd.de.pl
> new file mode 100644
> index 000000000..910225242
> --- /dev/null
> +++ b/config/zabbix_agentd/zabbix_agentd.de.pl
> @@ -0,0 +1,8 @@
> +%tr = ( 
> +%tr,
> +
> +'zabbix agent logs' => "Zabbix Agent-Protokolldateien",
> +
> +);
> +
> +#EOF
> diff --git a/config/zabbix_agentd/zabbix_agentd.en.pl b/config/zabbix_agentd/zabbix_agentd.en.pl
> new file mode 100644
> index 000000000..1f523f926
> --- /dev/null
> +++ b/config/zabbix_agentd/zabbix_agentd.en.pl
> @@ -0,0 +1,8 @@
> +%tr = ( 
> +%tr,
> +
> +'zabbix agent logs' => "Zabbix Agent Logs",
> +
> +);
> +
> +#EOF
> diff --git a/config/zabbix_agentd/zabbix_agentd.fr.pl b/config/zabbix_agentd/zabbix_agentd.fr.pl
> new file mode 100644
> index 000000000..f7576ad2f
> --- /dev/null
> +++ b/config/zabbix_agentd/zabbix_agentd.fr.pl
> @@ -0,0 +1,8 @@
> +%tr = ( 
> +%tr,
> +
> +'zabbix agent logs' => "Rapports de Zabbix Agent",
> +
> +);
> +
> +#EOF
> diff --git a/config/zabbix_agentd/zabbix_agentd.nl.pl b/config/zabbix_agentd/zabbix_agentd.nl.pl
> new file mode 100644
> index 000000000..1f523f926
> --- /dev/null
> +++ b/config/zabbix_agentd/zabbix_agentd.nl.pl
> @@ -0,0 +1,8 @@
> +%tr = ( 
> +%tr,
> +
> +'zabbix agent logs' => "Zabbix Agent Logs",
> +
> +);
> +
> +#EOF
> diff --git a/html/cgi-bin/logs.cgi/zabbix_agentd.dat b/html/cgi-bin/logs.cgi/zabbix_agentd.dat
> new file mode 100644
> index 000000000..047ca2e98
> --- /dev/null
> +++ b/html/cgi-bin/logs.cgi/zabbix_agentd.dat
> @@ -0,0 +1,341 @@
> +#!/usr/bin/perl
> +###############################################################################
> +#                                                                             #
> +# IPFire.org - A linux based firewall                                         #
> +# Copyright (C) 2020 IPFire Team  <info@ipfire.org>                           #
> +#                                                                             #
> +# This program is free software: you can redistribute it and/or modify        #
> +# it under the terms of the GNU General Public License as published by        #
> +# the Free Software Foundation, either version 3 of the License, or           #
> +# (at your option) any later version.                                         #
> +#                                                                             #
> +# This program is distributed in the hope that it will be useful,             #
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
> +# GNU General Public License for more details.                                #
> +#                                                                             #
> +# You should have received a copy of the GNU General Public License           #
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
> +#                                                                             #
> +###############################################################################
> +
> +use strict;
> +
> +# enable only the following on debugging purpose
> +# use warnings;
> +# use CGI::Carp 'fatalsToBrowser';
> +
> +require '/var/ipfire/general-functions.pl';
> +require "${General::swroot}/lang.pl";
> +require "${General::swroot}/header.pl";
> +
> +my %color = ();
> +my %mainsettings = ();
> +&General::readhash("${General::swroot}/main/settings", \%mainsettings);
> +&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
> +
> +use POSIX();
> +
> +my %cgiparams=();
> +my %logsettings=();
> +my $errormessage = '';
> +
> +my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
> + 'Sep', 'Oct', 'Nov', 'Dec' );
> +my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'}, $Lang::tr{'march'},
> + $Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'}, $Lang::tr{'july'}, $Lang::tr{'august'},
> + $Lang::tr{'september'}, $Lang::tr{'october'}, $Lang::tr{'november'},
> + $Lang::tr{'december'} );
> +
> +my @now = localtime();
> +my $dow = $now[6];
> +my $doy = $now[7];
> +my $tdoy = $now[7];
> +my $year = $now[5]+1900;
> +
> +$cgiparams{'DAY'} = $now[3];
> +$cgiparams{'MONTH'} = $now[4];
> +$cgiparams{'ACTION'} = '';
> +
> +&Header::getcgihash(\%cgiparams);
> +$logsettings{'LOGVIEW_REVERSE'} = 'off';
> +&General::readhash("${General::swroot}/logging/settings", \%logsettings);
> +${Header::viewsize} = defined ($logsettings{'LOGVIEW_VIEWSIZE'}) ? $logsettings{'LOGVIEW_VIEWSIZE'} : 150;
> +
> +my $start = ($logsettings{'LOGVIEW_REVERSE'} eq 'on') ? 0x7FFFF000 : 0; #index of first line number to display
> +
> +if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne $Lang::tr{'update'}) {
> + my @temp = split(',',$ENV{'QUERY_STRING'});
> + $start = $temp[0];
> + $cgiparams{'MONTH'} = $temp[1];
> + $cgiparams{'DAY'} = $temp[2];
> +}
> +
> +if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
> + !($cgiparams{'DAY'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)$/)) {
> + $cgiparams{'DAY'} = $now[3];
> + $cgiparams{'MONTH'} = $now[4];
> +} elsif($cgiparams{'ACTION'} eq '>>') {
> + my @temp_then=();
> + my @temp_now = localtime(time);
> + $temp_now[4] = $cgiparams{'MONTH'};
> + $temp_now[3] = $cgiparams{'DAY'};
> + @temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
> + ## Retrieve the same time on the next day +
> + ## 86400 seconds in a day
> + $cgiparams{'MONTH'} = $temp_then[4];
> + $cgiparams{'DAY'} = $temp_then[3];
> +} elsif($cgiparams{'ACTION'} eq '<<') {
> + my @temp_then=();
> + my @temp_now = localtime(time);
> + $temp_now[4] = $cgiparams{'MONTH'};
> + $temp_now[3] = $cgiparams{'DAY'};
> + @temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
> + ## Retrieve the same time on the next day -
> + ## 86400 seconds in a day
> + $cgiparams{'MONTH'} = $temp_then[4];
> + $cgiparams{'DAY'} = $temp_then[3];
> +}
> +
> +# Find in which file.gz is the log. Can be calculated because MONTHLY ROTATING of zabbix_agentd.log
> +my $gzindex;
> +my $date = $cgiparams{'DAY'} == 0 ? '' :  $cgiparams{'DAY'} <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
> +
> +my @then = ();
> +
> +my $monthstr = ($cgiparams{'MONTH'} + 1) <= 9 ? "0" . ($cgiparams{'MONTH'} + 1) : ($cgiparams{'MONTH'} + 1);
> +my $daystr =  $cgiparams{'DAY'} == 0 ?  '..' : $cgiparams{'DAY'} <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
> +my $yearstr = $year;
> +
> +# Calculate time. If future date, calculate for past year !!!
> +if (( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} > $now[3]) ||
> + ( $cgiparams{'MONTH'}  > $now[4] ) ) {
> + @then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1901 ));
> + $date = "$longmonths[$cgiparams{'MONTH'}] $date, ". int($year-1);
> + $yearstr--;
> +} else {
> + @then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1900 ));
> + $date = "$longmonths[$cgiparams{'MONTH'}] $date, $year";
> +}
> +
> +$gzindex = $now[4] - $then[4];
> +$gzindex += 12 if $gzindex < 0;
> +
> +my $lines = 0;
> +my @log=();
> +
> +my $loop = 1;
> +my $filestr = 0;
> +my $search_for_end = 0;
> +
> +while ($gzindex >=0 && $loop) {
> + # calculate file name
> + if ($gzindex == 0) {
> + $filestr = "/var/log/zabbix/zabbix_agentd.log";
> + } else {
> + $filestr = "/var/log/zabbix/zabbix_agentd.log.$gzindex";
> + $filestr = "$filestr.gz" if -f "$filestr.gz";
> + }
> + # now read file if existing
> + if (open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr))) {
> +    READ:while (<FILE>) {
> + my $line = $_;
> + if ($line =~ /^ *[0-9]+:${yearstr}${monthstr}${daystr}:[0-9]{6}\.[0-9]{3} (.*)/) {
> + # when standard viewing, just keep in memory the correct slice
> + # it starts at '$start' and size is $viewport
> + # If export, then keep all lines...
> + if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}){
> + $log[$lines++] = "$line";
> + } else {
> + if ($lines++ < ($start + $Header::viewsize)) {
> + push(@log,"$line");
> + if (@log > $Header::viewsize) {
> + shift (@log);
> + }
> + }
> + }
> + $search_for_end = 1; # we find the start of slice, can look for end now
> + } else {
> + if ($search_for_end == 1) {
> + #finish read files when date is over (test month equality only)
> + $line =~ /^ *[0-9]+:[0-9]{4}([0-9]{2})([0-9]{2}):[0-9]{6}\.[0-9]{3} .*$/;
> + $loop = 0 if ( ($1 ne $monthstr) || ( ($daystr ne '..') && ($daystr ne $2) ) );
> + }
> + }
> +    }
> +    close (FILE);
> + }
> + $gzindex--;     # will try next gz file eg 40,39,38,.... because it may have holes
> +}
> +
> +if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}) {
> + print "Content-type: text/plain\n\n";
> + print "IPFire $Lang::tr{'zabbix agent logs'}\r\n";
> + print "$Lang::tr{'date'}: $date\r\n\r\n";
> +
> + if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
> +
> + foreach $_ (@log) {
> + /^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-9]{2}\.[0-9]{3}) (.*)$/;
> + my $pid = $1;
> + my $day = $2;
> + $day =~ tr / /0/;
> + my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
> + print "$time ($pid) $6\r\n";
> + }
> + exit 0;
> +}
> +
> +&Header::showhttpheaders();
> +
> +&Header::openpage($Lang::tr{'zabbix agent logs'}, 1, '');
> +
> +&Header::openbigbox('100%', 'left', '', $errormessage);
> +
> +if ($errormessage) {
> + &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
> + print "<font class='base'>$errormessage&nbsp;</font>\n";
> + &Header::closebox();
> +}
> +
> +&Header::openbox('100%', 'left', "$Lang::tr{'settings'}:");
> +
> +print <<END
> +<form method='post' action='$ENV{'SCRIPT_NAME'}'>
> +<table width='100%'>
> +<tr>
> + <td width='10%' class='base'>$Lang::tr{'month'}:</td>
> + <td width='25%'>
> + <select name='MONTH'>
> +END
> +;
> +for (my $month = 0; $month < 12; $month++) {
> + print "\t<option ";
> + if ($month == $cgiparams{'MONTH'}) {
> + print "selected='selected' "; }
> + print "value='$month'>$longmonths[$month]</option>\n";
> +}
> +print <<END
> + </select>
> + </td>
> + <td width='10%' class='base'>$Lang::tr{'day'}:</td>
> + <td width='25%'>
> + <select name='DAY'>
> +END
> +;
> +print "<option value='0'>$Lang::tr{'all'}</option>\n";
> +for (my $day = 1; $day <= 31; $day++) {
> + print "\t<option ";
> + if ($day == $cgiparams{'DAY'}) {
> + print "selected='selected' "; }
> + print "value='$day'>$day</option>\n";
> +}
> +print <<END
> +</select>
> +</td>
> +<td width='5%'  align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
> +<td width='5%'  align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
> +<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' /></td>
> +<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'export'}' /></td>
> +</tr>
> +</table>
> +</form>
> +END
> +;
> +
> +&Header::closebox();
> +
> +&Header::openbox('100%', 'left', $Lang::tr{'log'});
> +print "<p><b>$Lang::tr{'total hits for log section'} $date: $lines</b></p>";
> +
> +$start = $lines - ${Header::viewsize} if ($start >= $lines - ${Header::viewsize});
> +$start = 0 if ($start < 0);
> +
> +my $prev;
> +if ($start == 0) {
> + $prev = -1;
> +} else {
> + $prev = $start - ${Header::viewsize};
> + $prev = 0 if ( $prev < 0);
> +}
> +
> +my $next;
> +if ($start == $lines - ${Header::viewsize}) {
> + $next = -1;
> +} else {
> + $next = $start + ${Header::viewsize};
> + $next = $lines - ${Header::viewsize} if ($next >= $lines - ${Header::viewsize});
> +}
> +
> +if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
> +if ($lines != 0) { &oldernewer(); }
> +
> +print <<END
> +<table width='100%' class='tbl'>
> +<tr>
> + <th width='15%' align='center' class='boldbase'><b>$Lang::tr{'time'}</b></th>
> + <th width='10%' align='center' class='boldbase'><b>PID</b></th>
> + <th width='75%'>&nbsp;</th>
> +</tr>
> +END
> +;
> +
> +$lines = 0;
> +foreach $_ (@log) {
> + /^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-9]{2}\.[0-9]{3}) (.*)$/;
> + my $pid = $1;
> + my $day = $2;
> + $day =~ tr / /0/;
> + my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
> + my $data = $6;
> + my $col="";
> +
> + if ($lines % 2) {
> + print "<tr>";
> + $col="bgcolor='$color{'color20'}'"; 
> + } else {
> + print "<tr>";
> + $col="bgcolor='$color{'color22'}'"; 
> + }
> + print "<td $col>$time<td $col>$pid<td $col>" .&Header::cleanhtml ("$data", 'y') . "</td></tr>\n";
> + $lines++;
> +}
> +print "</table>";
> +
> +&oldernewer();
> +
> +&Header::closebox();
> +
> +&Header::closebigbox();
> +
> +&Header::closepage();
> +
> +sub oldernewer {
> + print <<END
> +<table width='100%'>
> +<tr>
> +END
> + ;
> +
> + print "<td align='center' width='50%'>";
> + if ($prev != -1) {
> + print "<a href='/cgi-bin/logs.cgi/zabbix_agentd.dat?$prev,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'older'}</a>"; 
> + } else {
> + print "$Lang::tr{'older'}"; 
> + }
> + print "</td>\n";
> +
> + print "<td align='center' width='50%'>";
> + if ($next >= 0) {
> + print "<a href='/cgi-bin/logs.cgi/zabbix_agentd.dat?$next,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'newer'}</a>"; 
> + } else {
> + print "$Lang::tr{'newer'}"; 
> + }
> + print "</td>\n";
> +
> + print <<END
> +</tr>
> +</table>
> +END
> + ;
> +}
> diff --git a/lfs/zabbix_agentd b/lfs/zabbix_agentd
> index 281bd9fa3..49b8440f8 100644
> --- a/lfs/zabbix_agentd
> +++ b/lfs/zabbix_agentd
> @@ -139,6 +139,10 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
> -mkdir -pv /etc/logrotate.d
> install -v -m 644 $(DIR_SRC)/config/zabbix_agentd/logrotate \
> /etc/logrotate.d/zabbix_agentd
> + 
> + # Install addon-specific language-files.
> + install -v -m 004 $(DIR_SRC)/config/zabbix_agentd/zabbix_agentd.*.pl \
> + /var/ipfire/addon-lang/
> 
> @rm -rf $(DIR_APP)
> @$(POSTBUILD)
> diff --git a/src/paks/zabbix_agentd/install.sh b/src/paks/zabbix_agentd/install.sh
> index 80632d1ec..465ea7e8a 100644
> --- a/src/paks/zabbix_agentd/install.sh
> +++ b/src/paks/zabbix_agentd/install.sh
> @@ -32,6 +32,7 @@ if ! getent passwd zabbix; then
> fi
> 
> extract_files
> +/usr/local/bin/update-lang-cache
> 
> # Create symlinks for runlevel interaction.
> ln -sf ../init.d/zabbix_agentd /etc/rc.d/rc3.d/S65zabbix_agentd
> diff --git a/src/paks/zabbix_agentd/uninstall.sh b/src/paks/zabbix_agentd/uninstall.sh
> index edff3b818..4342384de 100644
> --- a/src/paks/zabbix_agentd/uninstall.sh
> +++ b/src/paks/zabbix_agentd/uninstall.sh
> @@ -25,6 +25,7 @@
> stop_service ${NAME}
> make_backup ${NAME}
> remove_files
> +/usr/local/bin/update-lang-cache
> 
> # Remove init-scripts and symlinks
> rm -rfv /etc/rc.d/rc*.d/*zabbix_agentd
> diff --git a/src/paks/zabbix_agentd/update.sh b/src/paks/zabbix_agentd/update.sh
> index a41e72ab4..f01e32810 100644
> --- a/src/paks/zabbix_agentd/update.sh
> +++ b/src/paks/zabbix_agentd/update.sh
> @@ -40,6 +40,9 @@ if [ -f /etc/sudoers.d/zabbix ]; then
> fi
> fi
> 
> +# Fix permissions on /var/log/zabbix/* to allow GUI to read the logfiles.
> +find /var/log/zabbix -perm 640 -exec chmod 644 \{\} \;
> +
> extract_backup_includes
> ./uninstall.sh
> ./install.sh
> -- 
> 2.40.0
> 
> 
> -- 
> Dit bericht is gescanned op virussen en andere gevaarlijke
> inhoud door MailScanner en lijkt schoon te zijn.
>
  
Robin Roevens April 11, 2023, 8:33 p.m. UTC | #2
Hi Michael

Michael Tremer schreef op di 11-04-2023 om 13:48 [+0100]:
> Hello Robin,
> 
> Thanks for the patch.
> 
> > On 2 Apr 2023, at 12:07, Robin Roevens <robin.roevens@disroot.org>
> > wrote:
> > 
> > - Adds a simple logs viewer page logs.cgi/zabbix_agentd.dat, based
> >  on logs.cgi/logs.dat, to the Logs menu in GUI.
> 
> Why is an extra CGI script needed? Could not this not be integrated
> into logs.dat?

I don't see how to integrate it into logs.dat as a conditional item
only displayed when the addon is installed in a clean way and without
'contaminating' ipfire core wui files with too much addon-specific
code.

Logs.dat is currently designed to read syslog-style formatted logging
lines (from /var/log/messages and /var/log/mail) but for zabbix_agent
(/var/log/zabbix/zabbix_agentd.log) both the line format and the
date/time format of the zabbix_agentd logs are different, as is the log
rotation frequency (monthly vs weekly). 

This would mean I would have to have implement an alternative log-file-
index calculation, and different regexes for parsing log lines when
zabbix_agent is selected in logs.dat and even conditionally
reformatting the log-line itself by adding the logging PID to it in a
clear way. 
I don't see how I would be able to do that in a clean way in the
current code. And again, I don't think it would be a good idea to add
too much addon-specific code in core wui files.

Better would be that logs.dat is rewritten, mainly from scratch I
think, to be a modular viewer with the ability for addons to add
specifications by dropping a config or even perl script somewhere for
example overloading functions for parsing the log lines format,
calculating rotation file indexes, columns to display in the ui, etc.
But that is not immediately something that I can pull out of my sleeve
some time soon :-)

So until someone does implement such a modular logs viewer, I think
this is the best and easiest alternative with this code explicitly only
installed when the addon is installed.

Regards 

Robin

> -Michael
> 
> > - Changes permission of zabbix_agentd logfiles in logrotate config
> >  for GUI to be able to access the log files (640 to 644)
> > - Changes file permissions of existing zabbix_agentd logfiles upon
> >  update of the package
> > - Rootfile changes: added gui page, menu item-file, and addon
> >  language files
> > - configroot rootfile changes: added logs menu item-file as comment
> > - web-user-interface rootfile changes: added log viewer .dat as
> > comment
> > - Update language cache during install/uninstall
> > 
> > Signed-off-by: Robin Roevens <robin.roevens@disroot.org>
> > ---
> > config/menu/EX-zabbix_agentd.menu          |   5 +
> > config/rootfiles/common/configroot         |   1 +
> > config/rootfiles/common/web-user-interface |   1 +
> > config/rootfiles/packages/zabbix_agentd    |   6 +
> > config/zabbix_agentd/logrotate             |   2 +-
> > config/zabbix_agentd/zabbix_agentd.de.pl   |   8 +
> > config/zabbix_agentd/zabbix_agentd.en.pl   |   8 +
> > config/zabbix_agentd/zabbix_agentd.fr.pl   |   8 +
> > config/zabbix_agentd/zabbix_agentd.nl.pl   |   8 +
> > html/cgi-bin/logs.cgi/zabbix_agentd.dat    | 341
> > +++++++++++++++++++++
> > lfs/zabbix_agentd                          |   4 +
> > src/paks/zabbix_agentd/install.sh          |   1 +
> > src/paks/zabbix_agentd/uninstall.sh        |   1 +
> > src/paks/zabbix_agentd/update.sh           |   3 +
> > 14 files changed, 396 insertions(+), 1 deletion(-)
> > create mode 100644 config/menu/EX-zabbix_agentd.menu
> > create mode 100644 config/zabbix_agentd/zabbix_agentd.de.pl
> > create mode 100644 config/zabbix_agentd/zabbix_agentd.en.pl
> > create mode 100644 config/zabbix_agentd/zabbix_agentd.fr.pl
> > create mode 100644 config/zabbix_agentd/zabbix_agentd.nl.pl
> > create mode 100644 html/cgi-bin/logs.cgi/zabbix_agentd.dat
> > 
> > diff --git a/config/menu/EX-zabbix_agentd.menu b/config/menu/EX-
> > zabbix_agentd.menu
> > new file mode 100644
> > index 000000000..dddd7f05e
> > --- /dev/null
> > +++ b/config/menu/EX-zabbix_agentd.menu
> > @@ -0,0 +1,5 @@
> > + $sublogs->{'95.zabbixagent'} = {'caption' => $Lang::tr{'zabbix
> > agent logs'},
> > + 'uri' => '/cgi-bin/logs.cgi/zabbix_agentd.dat',
> > + 'title' => "$Lang::tr{'zabbix agent logs'}",
> > + 'enabled' => 1
> > + };
> > diff --git a/config/rootfiles/common/configroot
> > b/config/rootfiles/common/configroot
> > index bc979cf2c..f12e2e0f0 100644
> > --- a/config/rootfiles/common/configroot
> > +++ b/config/rootfiles/common/configroot
> > @@ -126,6 +126,7 @@ var/ipfire/menu.d/70-log.menu
> > #var/ipfire/menu.d/EX-samba.menu
> > #var/ipfire/menu.d/EX-tor.menu
> > #var/ipfire/menu.d/EX-wlanap.menu
> > +#var/ipfire/menu.d/EX-zabbix_agentd.menu
> > var/ipfire/modem
> > var/ipfire/modem-lib.pl
> > #var/ipfire/modem/defaults
> > diff --git a/config/rootfiles/common/web-user-interface
> > b/config/rootfiles/common/web-user-interface
> > index 33f0d30a7..bc17b4ce4 100644
> > --- a/config/rootfiles/common/web-user-interface
> > +++ b/config/rootfiles/common/web-user-interface
> > @@ -49,6 +49,7 @@ srv/web/ipfire/cgi-
> > bin/logs.cgi/showrequestfromip.dat
> > srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromport.dat
> > srv/web/ipfire/cgi-bin/logs.cgi/summary.dat
> > srv/web/ipfire/cgi-bin/logs.cgi/urlfilter.dat
> > +#srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
> > srv/web/ipfire/cgi-bin/mac.cgi
> > srv/web/ipfire/cgi-bin/mail.cgi
> > srv/web/ipfire/cgi-bin/mdstat.cgi
> > diff --git a/config/rootfiles/packages/zabbix_agentd
> > b/config/rootfiles/packages/zabbix_agentd
> > index 6f2c831d7..5b57026f5 100644
> > --- a/config/rootfiles/packages/zabbix_agentd
> > +++ b/config/rootfiles/packages/zabbix_agentd
> > @@ -7,6 +7,7 @@ etc/zabbix_agentd/scripts
> > etc/zabbix_agentd/zabbix_agentd.conf
> > etc/zabbix_agentd/zabbix_agentd.conf.example
> > etc/zabbix_agentd/zabbix_agentd.d
> > +srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
> > usr/bin/zabbix_get
> > usr/bin/zabbix_sender
> > #usr/lib/modules
> > @@ -16,6 +17,11 @@ usr/sbin/zabbix_agentd
> > #usr/share/man/man1/zabbix_sender.1
> > #usr/share/man/man8/zabbix_agentd.8
> > var/ipfire/backup/addons/includes/zabbix_agentd
> > +var/ipfire/addon-lang/zabbix_agentd.de.pl
> > +var/ipfire/addon-lang/zabbix_agentd.en.pl
> > +var/ipfire/addon-lang/zabbix_agentd.fr.pl
> > +var/ipfire/addon-lang/zabbix_agentd.nl.pl
> > +var/ipfire/menu.d/EX-zabbix_agentd.menu
> > var/ipfire/zabbix_agentd
> > var/ipfire/zabbix_agentd/zabbix_agentd_ipfire_mandatory.conf
> > var/ipfire/zabbix_agentd/userparameters
> > diff --git a/config/zabbix_agentd/logrotate
> > b/config/zabbix_agentd/logrotate
> > index 83bbca9fb..46fee44f2 100644
> > --- a/config/zabbix_agentd/logrotate
> > +++ b/config/zabbix_agentd/logrotate
> > @@ -5,5 +5,5 @@
> >     delaycompress
> >     missingok
> >     notifempty
> > -    create 0640 zabbix zabbix
> > +    create 0644 zabbix zabbix
> > }
> > diff --git a/config/zabbix_agentd/zabbix_agentd.de.pl
> > b/config/zabbix_agentd/zabbix_agentd.de.pl
> > new file mode 100644
> > index 000000000..910225242
> > --- /dev/null
> > +++ b/config/zabbix_agentd/zabbix_agentd.de.pl
> > @@ -0,0 +1,8 @@
> > +%tr = ( 
> > +%tr,
> > +
> > +'zabbix agent logs' => "Zabbix Agent-Protokolldateien",
> > +
> > +);
> > +
> > +#EOF
> > diff --git a/config/zabbix_agentd/zabbix_agentd.en.pl
> > b/config/zabbix_agentd/zabbix_agentd.en.pl
> > new file mode 100644
> > index 000000000..1f523f926
> > --- /dev/null
> > +++ b/config/zabbix_agentd/zabbix_agentd.en.pl
> > @@ -0,0 +1,8 @@
> > +%tr = ( 
> > +%tr,
> > +
> > +'zabbix agent logs' => "Zabbix Agent Logs",
> > +
> > +);
> > +
> > +#EOF
> > diff --git a/config/zabbix_agentd/zabbix_agentd.fr.pl
> > b/config/zabbix_agentd/zabbix_agentd.fr.pl
> > new file mode 100644
> > index 000000000..f7576ad2f
> > --- /dev/null
> > +++ b/config/zabbix_agentd/zabbix_agentd.fr.pl
> > @@ -0,0 +1,8 @@
> > +%tr = ( 
> > +%tr,
> > +
> > +'zabbix agent logs' => "Rapports de Zabbix Agent",
> > +
> > +);
> > +
> > +#EOF
> > diff --git a/config/zabbix_agentd/zabbix_agentd.nl.pl
> > b/config/zabbix_agentd/zabbix_agentd.nl.pl
> > new file mode 100644
> > index 000000000..1f523f926
> > --- /dev/null
> > +++ b/config/zabbix_agentd/zabbix_agentd.nl.pl
> > @@ -0,0 +1,8 @@
> > +%tr = ( 
> > +%tr,
> > +
> > +'zabbix agent logs' => "Zabbix Agent Logs",
> > +
> > +);
> > +
> > +#EOF
> > diff --git a/html/cgi-bin/logs.cgi/zabbix_agentd.dat b/html/cgi-
> > bin/logs.cgi/zabbix_agentd.dat
> > new file mode 100644
> > index 000000000..047ca2e98
> > --- /dev/null
> > +++ b/html/cgi-bin/logs.cgi/zabbix_agentd.dat
> > @@ -0,0 +1,341 @@
> > +#!/usr/bin/perl
> > +##################################################################
> > #############
> > +#                                                                 
> >             #
> > +# IPFire.org - A linux based
> > firewall                                         #
> > +# Copyright (C) 2020 IPFire Team 
> > <info@ipfire.org>                           #
> > +#                                                                 
> >             #
> > +# This program is free software: you can redistribute it and/or
> > modify        #
> > +# it under the terms of the GNU General Public License as
> > published by        #
> > +# the Free Software Foundation, either version 3 of the License,
> > or           #
> > +# (at your option) any later
> > version.                                         #
> > +#                                                                 
> >             #
> > +# This program is distributed in the hope that it will be
> > useful,             #
> > +# but WITHOUT ANY WARRANTY; without even the implied warranty
> > of              #
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> > the               #
> > +# GNU General Public License for more
> > details.                                #
> > +#                                                                 
> >             #
> > +# You should have received a copy of the GNU General Public
> > License           #
> > +# along with this program.  If not, see
> > <http://www.gnu.org/licenses/>.       #
> > +#                                                                 
> >             #
> > +##################################################################
> > #############
> > +
> > +use strict;
> > +
> > +# enable only the following on debugging purpose
> > +# use warnings;
> > +# use CGI::Carp 'fatalsToBrowser';
> > +
> > +require '/var/ipfire/general-functions.pl';
> > +require "${General::swroot}/lang.pl";
> > +require "${General::swroot}/header.pl";
> > +
> > +my %color = ();
> > +my %mainsettings = ();
> > +&General::readhash("${General::swroot}/main/settings",
> > \%mainsettings);
> > +&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/col
> > ors.txt", \%color);
> > +
> > +use POSIX();
> > +
> > +my %cgiparams=();
> > +my %logsettings=();
> > +my $errormessage = '';
> > +
> > +my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
> > 'Jul', 'Aug',
> > + 'Sep', 'Oct', 'Nov', 'Dec' );
> > +my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'},
> > $Lang::tr{'march'},
> > + $Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'},
> > $Lang::tr{'july'}, $Lang::tr{'august'},
> > + $Lang::tr{'september'}, $Lang::tr{'october'},
> > $Lang::tr{'november'},
> > + $Lang::tr{'december'} );
> > +
> > +my @now = localtime();
> > +my $dow = $now[6];
> > +my $doy = $now[7];
> > +my $tdoy = $now[7];
> > +my $year = $now[5]+1900;
> > +
> > +$cgiparams{'DAY'} = $now[3];
> > +$cgiparams{'MONTH'} = $now[4];
> > +$cgiparams{'ACTION'} = '';
> > +
> > +&Header::getcgihash(\%cgiparams);
> > +$logsettings{'LOGVIEW_REVERSE'} = 'off';
> > +&General::readhash("${General::swroot}/logging/settings",
> > \%logsettings);
> > +${Header::viewsize} = defined ($logsettings{'LOGVIEW_VIEWSIZE'}) ?
> > $logsettings{'LOGVIEW_VIEWSIZE'} : 150;
> > +
> > +my $start = ($logsettings{'LOGVIEW_REVERSE'} eq 'on') ? 0x7FFFF000
> > : 0; #index of first line number to display
> > +
> > +if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne
> > $Lang::tr{'update'}) {
> > + my @temp = split(',',$ENV{'QUERY_STRING'});
> > + $start = $temp[0];
> > + $cgiparams{'MONTH'} = $temp[1];
> > + $cgiparams{'DAY'} = $temp[2];
> > +}
> > +
> > +if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
> > + !($cgiparams{'DAY'} =~
> > /^(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24
> > |25|26|27|28|29|30|31)$/)) {
> > + $cgiparams{'DAY'} = $now[3];
> > + $cgiparams{'MONTH'} = $now[4];
> > +} elsif($cgiparams{'ACTION'} eq '>>') {
> > + my @temp_then=();
> > + my @temp_now = localtime(time);
> > + $temp_now[4] = $cgiparams{'MONTH'};
> > + $temp_now[3] = $cgiparams{'DAY'};
> > + @temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
> > + ## Retrieve the same time on the next day +
> > + ## 86400 seconds in a day
> > + $cgiparams{'MONTH'} = $temp_then[4];
> > + $cgiparams{'DAY'} = $temp_then[3];
> > +} elsif($cgiparams{'ACTION'} eq '<<') {
> > + my @temp_then=();
> > + my @temp_now = localtime(time);
> > + $temp_now[4] = $cgiparams{'MONTH'};
> > + $temp_now[3] = $cgiparams{'DAY'};
> > + @temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
> > + ## Retrieve the same time on the next day -
> > + ## 86400 seconds in a day
> > + $cgiparams{'MONTH'} = $temp_then[4];
> > + $cgiparams{'DAY'} = $temp_then[3];
> > +}
> > +
> > +# Find in which file.gz is the log. Can be calculated because
> > MONTHLY ROTATING of zabbix_agentd.log
> > +my $gzindex;
> > +my $date = $cgiparams{'DAY'} == 0 ? '' :  $cgiparams{'DAY'} <= 9 ?
> > "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
> > +
> > +my @then = ();
> > +
> > +my $monthstr = ($cgiparams{'MONTH'} + 1) <= 9 ? "0" .
> > ($cgiparams{'MONTH'} + 1) : ($cgiparams{'MONTH'} + 1);
> > +my $daystr =  $cgiparams{'DAY'} == 0 ?  '..' : $cgiparams{'DAY'}
> > <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
> > +my $yearstr = $year;
> > +
> > +# Calculate time. If future date, calculate for past year !!!
> > +if (( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} >
> > $now[3]) ||
> > + ( $cgiparams{'MONTH'}  > $now[4] ) ) {
> > + @then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'},
> > $cgiparams{'MONTH'}, $year - 1901 ));
> > + $date = "$longmonths[$cgiparams{'MONTH'}] $date, ". int($year-1);
> > + $yearstr--;
> > +} else {
> > + @then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'},
> > $cgiparams{'MONTH'}, $year - 1900 ));
> > + $date = "$longmonths[$cgiparams{'MONTH'}] $date, $year";
> > +}
> > +
> > +$gzindex = $now[4] - $then[4];
> > +$gzindex += 12 if $gzindex < 0;
> > +
> > +my $lines = 0;
> > +my @log=();
> > +
> > +my $loop = 1;
> > +my $filestr = 0;
> > +my $search_for_end = 0;
> > +
> > +while ($gzindex >=0 && $loop) {
> > + # calculate file name
> > + if ($gzindex == 0) {
> > + $filestr = "/var/log/zabbix/zabbix_agentd.log";
> > + } else {
> > + $filestr = "/var/log/zabbix/zabbix_agentd.log.$gzindex";
> > + $filestr = "$filestr.gz" if -f "$filestr.gz";
> > + }
> > + # now read file if existing
> > + if (open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" :
> > $filestr))) {
> > +    READ:while (<FILE>) {
> > + my $line = $_;
> > + if ($line =~ /^ *[0-9]+:${yearstr}${monthstr}${daystr}:[0-
> > 9]{6}\.[0-9]{3} (.*)/) {
> > + # when standard viewing, just keep in memory the correct slice
> > + # it starts at '$start' and size is $viewport
> > + # If export, then keep all lines...
> > + if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}){
> > + $log[$lines++] = "$line";
> > + } else {
> > + if ($lines++ < ($start + $Header::viewsize)) {
> > + push(@log,"$line");
> > + if (@log > $Header::viewsize) {
> > + shift (@log);
> > + }
> > + }
> > + }
> > + $search_for_end = 1; # we find the start of slice, can look for
> > end now
> > + } else {
> > + if ($search_for_end == 1) {
> > + #finish read files when date is over (test month equality only)
> > + $line =~ /^ *[0-9]+:[0-9]{4}([0-9]{2})([0-9]{2}):[0-9]{6}\.[0-
> > 9]{3} .*$/;
> > + $loop = 0 if ( ($1 ne $monthstr) || ( ($daystr ne '..') &&
> > ($daystr ne $2) ) );
> > + }
> > + }
> > +    }
> > +    close (FILE);
> > + }
> > + $gzindex--;     # will try next gz file eg 40,39,38,.... because
> > it may have holes
> > +}
> > +
> > +if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}) {
> > + print "Content-type: text/plain\n\n";
> > + print "IPFire $Lang::tr{'zabbix agent logs'}\r\n";
> > + print "$Lang::tr{'date'}: $date\r\n\r\n";
> > +
> > + if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse
> > @log; }
> > +
> > + foreach $_ (@log) {
> > + /^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-
> > 9]{2}\.[0-9]{3}) (.*)$/;
> > + my $pid = $1;
> > + my $day = $2;
> > + $day =~ tr / /0/;
> > + my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
> > + print "$time ($pid) $6\r\n";
> > + }
> > + exit 0;
> > +}
> > +
> > +&Header::showhttpheaders();
> > +
> > +&Header::openpage($Lang::tr{'zabbix agent logs'}, 1, '');
> > +
> > +&Header::openbigbox('100%', 'left', '', $errormessage);
> > +
> > +if ($errormessage) {
> > + &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
> > + print "<font class='base'>$errormessage&nbsp;</font>\n";
> > + &Header::closebox();
> > +}
> > +
> > +&Header::openbox('100%', 'left', "$Lang::tr{'settings'}:");
> > +
> > +print <<END
> > +<form method='post' action='$ENV{'SCRIPT_NAME'}'>
> > +<table width='100%'>
> > +<tr>
> > + <td width='10%' class='base'>$Lang::tr{'month'}:</td>
> > + <td width='25%'>
> > + <select name='MONTH'>
> > +END
> > +;
> > +for (my $month = 0; $month < 12; $month++) {
> > + print "\t<option ";
> > + if ($month == $cgiparams{'MONTH'}) {
> > + print "selected='selected' "; }
> > + print "value='$month'>$longmonths[$month]</option>\n";
> > +}
> > +print <<END
> > + </select>
> > + </td>
> > + <td width='10%' class='base'>$Lang::tr{'day'}:</td>
> > + <td width='25%'>
> > + <select name='DAY'>
> > +END
> > +;
> > +print "<option value='0'>$Lang::tr{'all'}</option>\n";
> > +for (my $day = 1; $day <= 31; $day++) {
> > + print "\t<option ";
> > + if ($day == $cgiparams{'DAY'}) {
> > + print "selected='selected' "; }
> > + print "value='$day'>$day</option>\n";
> > +}
> > +print <<END
> > +</select>
> > +</td>
> > +<td width='5%'  align='center'><input type='submit' name='ACTION'
> > title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
> > +<td width='5%'  align='center'><input type='submit' name='ACTION'
> > title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
> > +<td width='10%' align='center'><input type='submit' name='ACTION'
> > value='$Lang::tr{'update'}' /></td>
> > +<td width='10%' align='center'><input type='submit' name='ACTION'
> > value='$Lang::tr{'export'}' /></td>
> > +</tr>
> > +</table>
> > +</form>
> > +END
> > +;
> > +
> > +&Header::closebox();
> > +
> > +&Header::openbox('100%', 'left', $Lang::tr{'log'});
> > +print "<p><b>$Lang::tr{'total hits for log section'} $date:
> > $lines</b></p>";
> > +
> > +$start = $lines - ${Header::viewsize} if ($start >= $lines -
> > ${Header::viewsize});
> > +$start = 0 if ($start < 0);
> > +
> > +my $prev;
> > +if ($start == 0) {
> > + $prev = -1;
> > +} else {
> > + $prev = $start - ${Header::viewsize};
> > + $prev = 0 if ( $prev < 0);
> > +}
> > +
> > +my $next;
> > +if ($start == $lines - ${Header::viewsize}) {
> > + $next = -1;
> > +} else {
> > + $next = $start + ${Header::viewsize};
> > + $next = $lines - ${Header::viewsize} if ($next >= $lines -
> > ${Header::viewsize});
> > +}
> > +
> > +if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse
> > @log; }
> > +if ($lines != 0) { &oldernewer(); }
> > +
> > +print <<END
> > +<table width='100%' class='tbl'>
> > +<tr>
> > + <th width='15%' align='center'
> > class='boldbase'><b>$Lang::tr{'time'}</b></th>
> > + <th width='10%' align='center' class='boldbase'><b>PID</b></th>
> > + <th width='75%'>&nbsp;</th>
> > +</tr>
> > +END
> > +;
> > +
> > +$lines = 0;
> > +foreach $_ (@log) {
> > + /^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-
> > 9]{2}\.[0-9]{3}) (.*)$/;
> > + my $pid = $1;
> > + my $day = $2;
> > + $day =~ tr / /0/;
> > + my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
> > + my $data = $6;
> > + my $col="";
> > +
> > + if ($lines % 2) {
> > + print "<tr>";
> > + $col="bgcolor='$color{'color20'}'"; 
> > + } else {
> > + print "<tr>";
> > + $col="bgcolor='$color{'color22'}'"; 
> > + }
> > + print "<td $col>$time<td $col>$pid<td $col>" .&Header::cleanhtml
> > ("$data", 'y') . "</td></tr>\n";
> > + $lines++;
> > +}
> > +print "</table>";
> > +
> > +&oldernewer();
> > +
> > +&Header::closebox();
> > +
> > +&Header::closebigbox();
> > +
> > +&Header::closepage();
> > +
> > +sub oldernewer {
> > + print <<END
> > +<table width='100%'>
> > +<tr>
> > +END
> > + ;
> > +
> > + print "<td align='center' width='50%'>";
> > + if ($prev != -1) {
> > + print "<a href='/cgi-
> > bin/logs.cgi/zabbix_agentd.dat?$prev,$cgiparams{'MONTH'},$cgiparams
> > {'DAY'}'>$Lang::tr{'older'}</a>"; 
> > + } else {
> > + print "$Lang::tr{'older'}"; 
> > + }
> > + print "</td>\n";
> > +
> > + print "<td align='center' width='50%'>";
> > + if ($next >= 0) {
> > + print "<a href='/cgi-
> > bin/logs.cgi/zabbix_agentd.dat?$next,$cgiparams{'MONTH'},$cgiparams
> > {'DAY'}'>$Lang::tr{'newer'}</a>"; 
> > + } else {
> > + print "$Lang::tr{'newer'}"; 
> > + }
> > + print "</td>\n";
> > +
> > + print <<END
> > +</tr>
> > +</table>
> > +END
> > + ;
> > +}
> > diff --git a/lfs/zabbix_agentd b/lfs/zabbix_agentd
> > index 281bd9fa3..49b8440f8 100644
> > --- a/lfs/zabbix_agentd
> > +++ b/lfs/zabbix_agentd
> > @@ -139,6 +139,10 @@ $(TARGET) : $(patsubst
> > %,$(DIR_DL)/%,$(objects))
> > -mkdir -pv /etc/logrotate.d
> > install -v -m 644 $(DIR_SRC)/config/zabbix_agentd/logrotate \
> > /etc/logrotate.d/zabbix_agentd
> > + 
> > + # Install addon-specific language-files.
> > + install -v -m 004
> > $(DIR_SRC)/config/zabbix_agentd/zabbix_agentd.*.pl \
> > + /var/ipfire/addon-lang/
> > 
> > @rm -rf $(DIR_APP)
> > @$(POSTBUILD)
> > diff --git a/src/paks/zabbix_agentd/install.sh
> > b/src/paks/zabbix_agentd/install.sh
> > index 80632d1ec..465ea7e8a 100644
> > --- a/src/paks/zabbix_agentd/install.sh
> > +++ b/src/paks/zabbix_agentd/install.sh
> > @@ -32,6 +32,7 @@ if ! getent passwd zabbix; then
> > fi
> > 
> > extract_files
> > +/usr/local/bin/update-lang-cache
> > 
> > # Create symlinks for runlevel interaction.
> > ln -sf ../init.d/zabbix_agentd /etc/rc.d/rc3.d/S65zabbix_agentd
> > diff --git a/src/paks/zabbix_agentd/uninstall.sh
> > b/src/paks/zabbix_agentd/uninstall.sh
> > index edff3b818..4342384de 100644
> > --- a/src/paks/zabbix_agentd/uninstall.sh
> > +++ b/src/paks/zabbix_agentd/uninstall.sh
> > @@ -25,6 +25,7 @@
> > stop_service ${NAME}
> > make_backup ${NAME}
> > remove_files
> > +/usr/local/bin/update-lang-cache
> > 
> > # Remove init-scripts and symlinks
> > rm -rfv /etc/rc.d/rc*.d/*zabbix_agentd
> > diff --git a/src/paks/zabbix_agentd/update.sh
> > b/src/paks/zabbix_agentd/update.sh
> > index a41e72ab4..f01e32810 100644
> > --- a/src/paks/zabbix_agentd/update.sh
> > +++ b/src/paks/zabbix_agentd/update.sh
> > @@ -40,6 +40,9 @@ if [ -f /etc/sudoers.d/zabbix ]; then
> > fi
> > fi
> > 
> > +# Fix permissions on /var/log/zabbix/* to allow GUI to read the
> > logfiles.
> > +find /var/log/zabbix -perm 640 -exec chmod 644 \{\} \;
> > +
> > extract_backup_includes
> > ./uninstall.sh
> > ./install.sh
> > -- 
> > 2.40.0
> > 
> > 
> > -- 
> > Dit bericht is gescanned op virussen en andere gevaarlijke
> > inhoud door MailScanner en lijkt schoon te zijn.
> > 
> 
>
  

Patch

diff --git a/config/menu/EX-zabbix_agentd.menu b/config/menu/EX-zabbix_agentd.menu
new file mode 100644
index 000000000..dddd7f05e
--- /dev/null
+++ b/config/menu/EX-zabbix_agentd.menu
@@ -0,0 +1,5 @@ 
+	$sublogs->{'95.zabbixagent'} = {'caption' => $Lang::tr{'zabbix agent logs'},
+				'uri' => '/cgi-bin/logs.cgi/zabbix_agentd.dat',
+				'title' => "$Lang::tr{'zabbix agent logs'}",
+				'enabled' => 1
+				};
diff --git a/config/rootfiles/common/configroot b/config/rootfiles/common/configroot
index bc979cf2c..f12e2e0f0 100644
--- a/config/rootfiles/common/configroot
+++ b/config/rootfiles/common/configroot
@@ -126,6 +126,7 @@  var/ipfire/menu.d/70-log.menu
 #var/ipfire/menu.d/EX-samba.menu
 #var/ipfire/menu.d/EX-tor.menu
 #var/ipfire/menu.d/EX-wlanap.menu
+#var/ipfire/menu.d/EX-zabbix_agentd.menu
 var/ipfire/modem
 var/ipfire/modem-lib.pl
 #var/ipfire/modem/defaults
diff --git a/config/rootfiles/common/web-user-interface b/config/rootfiles/common/web-user-interface
index 33f0d30a7..bc17b4ce4 100644
--- a/config/rootfiles/common/web-user-interface
+++ b/config/rootfiles/common/web-user-interface
@@ -49,6 +49,7 @@  srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromip.dat
 srv/web/ipfire/cgi-bin/logs.cgi/showrequestfromport.dat
 srv/web/ipfire/cgi-bin/logs.cgi/summary.dat
 srv/web/ipfire/cgi-bin/logs.cgi/urlfilter.dat
+#srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
 srv/web/ipfire/cgi-bin/mac.cgi
 srv/web/ipfire/cgi-bin/mail.cgi
 srv/web/ipfire/cgi-bin/mdstat.cgi
diff --git a/config/rootfiles/packages/zabbix_agentd b/config/rootfiles/packages/zabbix_agentd
index 6f2c831d7..5b57026f5 100644
--- a/config/rootfiles/packages/zabbix_agentd
+++ b/config/rootfiles/packages/zabbix_agentd
@@ -7,6 +7,7 @@  etc/zabbix_agentd/scripts
 etc/zabbix_agentd/zabbix_agentd.conf
 etc/zabbix_agentd/zabbix_agentd.conf.example
 etc/zabbix_agentd/zabbix_agentd.d
+srv/web/ipfire/cgi-bin/logs.cgi/zabbix_agentd.dat
 usr/bin/zabbix_get
 usr/bin/zabbix_sender
 #usr/lib/modules
@@ -16,6 +17,11 @@  usr/sbin/zabbix_agentd
 #usr/share/man/man1/zabbix_sender.1
 #usr/share/man/man8/zabbix_agentd.8
 var/ipfire/backup/addons/includes/zabbix_agentd
+var/ipfire/addon-lang/zabbix_agentd.de.pl
+var/ipfire/addon-lang/zabbix_agentd.en.pl
+var/ipfire/addon-lang/zabbix_agentd.fr.pl
+var/ipfire/addon-lang/zabbix_agentd.nl.pl
+var/ipfire/menu.d/EX-zabbix_agentd.menu
 var/ipfire/zabbix_agentd
 var/ipfire/zabbix_agentd/zabbix_agentd_ipfire_mandatory.conf
 var/ipfire/zabbix_agentd/userparameters
diff --git a/config/zabbix_agentd/logrotate b/config/zabbix_agentd/logrotate
index 83bbca9fb..46fee44f2 100644
--- a/config/zabbix_agentd/logrotate
+++ b/config/zabbix_agentd/logrotate
@@ -5,5 +5,5 @@ 
     delaycompress
     missingok
     notifempty
-    create 0640 zabbix zabbix
+    create 0644 zabbix zabbix
 }
diff --git a/config/zabbix_agentd/zabbix_agentd.de.pl b/config/zabbix_agentd/zabbix_agentd.de.pl
new file mode 100644
index 000000000..910225242
--- /dev/null
+++ b/config/zabbix_agentd/zabbix_agentd.de.pl
@@ -0,0 +1,8 @@ 
+%tr = ( 
+%tr,
+
+'zabbix agent logs' => "Zabbix Agent-Protokolldateien",
+
+);
+
+#EOF
diff --git a/config/zabbix_agentd/zabbix_agentd.en.pl b/config/zabbix_agentd/zabbix_agentd.en.pl
new file mode 100644
index 000000000..1f523f926
--- /dev/null
+++ b/config/zabbix_agentd/zabbix_agentd.en.pl
@@ -0,0 +1,8 @@ 
+%tr = ( 
+%tr,
+
+'zabbix agent logs' => "Zabbix Agent Logs",
+
+);
+
+#EOF
diff --git a/config/zabbix_agentd/zabbix_agentd.fr.pl b/config/zabbix_agentd/zabbix_agentd.fr.pl
new file mode 100644
index 000000000..f7576ad2f
--- /dev/null
+++ b/config/zabbix_agentd/zabbix_agentd.fr.pl
@@ -0,0 +1,8 @@ 
+%tr = ( 
+%tr,
+
+'zabbix agent logs' => "Rapports de Zabbix Agent",
+
+);
+
+#EOF
diff --git a/config/zabbix_agentd/zabbix_agentd.nl.pl b/config/zabbix_agentd/zabbix_agentd.nl.pl
new file mode 100644
index 000000000..1f523f926
--- /dev/null
+++ b/config/zabbix_agentd/zabbix_agentd.nl.pl
@@ -0,0 +1,8 @@ 
+%tr = ( 
+%tr,
+
+'zabbix agent logs' => "Zabbix Agent Logs",
+
+);
+
+#EOF
diff --git a/html/cgi-bin/logs.cgi/zabbix_agentd.dat b/html/cgi-bin/logs.cgi/zabbix_agentd.dat
new file mode 100644
index 000000000..047ca2e98
--- /dev/null
+++ b/html/cgi-bin/logs.cgi/zabbix_agentd.dat
@@ -0,0 +1,341 @@ 
+#!/usr/bin/perl
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2020 IPFire Team  <info@ipfire.org>                           #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+use strict;
+
+# enable only the following on debugging purpose
+# use warnings;
+# use CGI::Carp 'fatalsToBrowser';
+
+require '/var/ipfire/general-functions.pl';
+require "${General::swroot}/lang.pl";
+require "${General::swroot}/header.pl";
+
+my %color = ();
+my %mainsettings = ();
+&General::readhash("${General::swroot}/main/settings", \%mainsettings);
+&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
+
+use POSIX();
+
+my %cgiparams=();
+my %logsettings=();
+my $errormessage = '';
+
+my @shortmonths = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
+	'Sep', 'Oct', 'Nov', 'Dec' );
+my @longmonths = ( $Lang::tr{'january'}, $Lang::tr{'february'}, $Lang::tr{'march'},
+	$Lang::tr{'april'}, $Lang::tr{'may'}, $Lang::tr{'june'}, $Lang::tr{'july'}, $Lang::tr{'august'},
+	$Lang::tr{'september'}, $Lang::tr{'october'}, $Lang::tr{'november'},
+	$Lang::tr{'december'} );
+
+my @now = localtime();
+my $dow = $now[6];
+my $doy = $now[7];
+my $tdoy = $now[7];
+my $year = $now[5]+1900;
+
+$cgiparams{'DAY'} = $now[3];
+$cgiparams{'MONTH'} = $now[4];
+$cgiparams{'ACTION'} = '';
+
+&Header::getcgihash(\%cgiparams);
+$logsettings{'LOGVIEW_REVERSE'} = 'off';
+&General::readhash("${General::swroot}/logging/settings", \%logsettings);
+${Header::viewsize} = defined ($logsettings{'LOGVIEW_VIEWSIZE'}) ? $logsettings{'LOGVIEW_VIEWSIZE'} : 150;
+
+my $start = ($logsettings{'LOGVIEW_REVERSE'} eq 'on') ? 0x7FFFF000 : 0; #index of first line number to display
+
+if ($ENV{'QUERY_STRING'} && $cgiparams{'ACTION'} ne $Lang::tr{'update'}) {
+	my @temp = split(',',$ENV{'QUERY_STRING'});
+	$start = $temp[0];
+	$cgiparams{'MONTH'} = $temp[1];
+	$cgiparams{'DAY'} = $temp[2];
+}
+
+if (!($cgiparams{'MONTH'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11)$/) ||
+	!($cgiparams{'DAY'} =~ /^(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)$/)) {
+	$cgiparams{'DAY'} = $now[3];
+	$cgiparams{'MONTH'} = $now[4];
+} elsif($cgiparams{'ACTION'} eq '>>') {
+	my @temp_then=();
+	my @temp_now = localtime(time);
+	$temp_now[4] = $cgiparams{'MONTH'};
+	$temp_now[3] = $cgiparams{'DAY'};
+	@temp_then = localtime(POSIX::mktime(@temp_now) + 86400);
+	## Retrieve the same time on the next day +
+	## 86400 seconds in a day
+	$cgiparams{'MONTH'} = $temp_then[4];
+	$cgiparams{'DAY'} = $temp_then[3];
+} elsif($cgiparams{'ACTION'} eq '<<') {
+	my @temp_then=();
+	my @temp_now = localtime(time);
+	$temp_now[4] = $cgiparams{'MONTH'};
+	$temp_now[3] = $cgiparams{'DAY'};
+	@temp_then = localtime(POSIX::mktime(@temp_now) - 86400);
+	## Retrieve the same time on the next day -
+	## 86400 seconds in a day
+	$cgiparams{'MONTH'} = $temp_then[4];
+	$cgiparams{'DAY'} = $temp_then[3];
+}
+
+# Find in which file.gz is the log. Can be calculated because MONTHLY ROTATING of zabbix_agentd.log
+my $gzindex;
+my $date = $cgiparams{'DAY'} == 0 ? '' :  $cgiparams{'DAY'} <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
+
+my @then = ();
+
+my $monthstr = ($cgiparams{'MONTH'} + 1) <= 9 ? "0" . ($cgiparams{'MONTH'} + 1) : ($cgiparams{'MONTH'} + 1);
+my $daystr =  $cgiparams{'DAY'} == 0 ?  '..' : $cgiparams{'DAY'} <= 9 ? "0$cgiparams{'DAY'}" : "$cgiparams{'DAY'}";
+my $yearstr = $year;
+
+# Calculate time. If future date, calculate for past year !!!
+if (( $cgiparams{'MONTH'} eq $now[4]) && ($cgiparams{'DAY'} > $now[3]) ||
+	( $cgiparams{'MONTH'}  > $now[4] ) ) {
+	@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1901 ));
+	$date = "$longmonths[$cgiparams{'MONTH'}] $date, ". int($year-1);
+	$yearstr--;
+} else {
+	@then = localtime(POSIX::mktime( 0, 0, 0, $cgiparams{'DAY'}, $cgiparams{'MONTH'}, $year - 1900 ));
+	$date = "$longmonths[$cgiparams{'MONTH'}] $date, $year";
+}
+
+$gzindex = $now[4] - $then[4];
+$gzindex += 12 if $gzindex < 0;
+
+my $lines = 0;
+my @log=();
+
+my $loop = 1;
+my $filestr = 0;
+my $search_for_end = 0;
+
+while ($gzindex >=0 && $loop) {
+	# calculate file name
+	if ($gzindex == 0) {
+		$filestr = "/var/log/zabbix/zabbix_agentd.log";
+	} else {
+		$filestr = "/var/log/zabbix/zabbix_agentd.log.$gzindex";
+		$filestr = "$filestr.gz" if -f "$filestr.gz";
+	}
+	# now read file if existing
+	if (open (FILE,($filestr =~ /.gz$/ ? "gzip -dc $filestr |" : $filestr))) {
+	    READ:while (<FILE>) {
+			my $line = $_;
+			if ($line =~ /^ *[0-9]+:${yearstr}${monthstr}${daystr}:[0-9]{6}\.[0-9]{3} (.*)/) {
+				# when standard viewing, just keep in memory the correct slice
+				# it starts at '$start' and size is $viewport
+				# If export, then keep all lines...
+				if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}){
+					$log[$lines++] = "$line";
+				} else {
+					if ($lines++ < ($start + $Header::viewsize)) {
+						push(@log,"$line");
+						if (@log > $Header::viewsize) {
+							shift (@log);
+						}
+					}
+				}
+				$search_for_end = 1;	# we find the start of slice, can look for end now
+			} else {
+				if ($search_for_end == 1) {
+					#finish read files when date is over (test month equality only)
+					$line =~ /^ *[0-9]+:[0-9]{4}([0-9]{2})([0-9]{2}):[0-9]{6}\.[0-9]{3} .*$/;
+					$loop = 0 if ( ($1 ne $monthstr) || ( ($daystr ne '..') && ($daystr ne $2) ) );
+				}
+			}
+	    }
+	    close (FILE);
+	}
+	$gzindex--;     # will try next gz file eg 40,39,38,.... because it may have holes
+}
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'export'}) {
+	print "Content-type: text/plain\n\n";
+	print "IPFire $Lang::tr{'zabbix agent logs'}\r\n";
+	print "$Lang::tr{'date'}: $date\r\n\r\n";
+
+	if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
+
+	foreach $_ (@log) {
+		/^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-9]{2}\.[0-9]{3}) (.*)$/;
+		my $pid = $1;
+		my $day = $2;
+		$day =~ tr / /0/;
+		my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
+		print "$time ($pid) $6\r\n";
+	}
+	exit 0;
+}
+
+&Header::showhttpheaders();
+
+&Header::openpage($Lang::tr{'zabbix agent logs'}, 1, '');
+
+&Header::openbigbox('100%', 'left', '', $errormessage);
+
+if ($errormessage) {
+	&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
+	print "<font class='base'>$errormessage&nbsp;</font>\n";
+	&Header::closebox();
+}
+
+&Header::openbox('100%', 'left', "$Lang::tr{'settings'}:");
+
+print <<END
+<form method='post' action='$ENV{'SCRIPT_NAME'}'>
+<table width='100%'>
+<tr>
+	<td width='10%' class='base'>$Lang::tr{'month'}:</td>
+	<td width='25%'>
+	<select name='MONTH'>
+END
+;
+for (my $month = 0; $month < 12; $month++) {
+	print "\t<option ";
+	if ($month == $cgiparams{'MONTH'}) {
+		print "selected='selected' "; }
+	print "value='$month'>$longmonths[$month]</option>\n";
+}
+print <<END
+	</select>
+	</td>
+	<td width='10%' class='base'>$Lang::tr{'day'}:</td>
+	<td width='25%'>
+	<select name='DAY'>
+END
+;
+print "<option value='0'>$Lang::tr{'all'}</option>\n";
+for (my $day = 1; $day <= 31; $day++) {
+	print "\t<option ";
+	if ($day == $cgiparams{'DAY'}) {
+		print "selected='selected' "; }
+	print "value='$day'>$day</option>\n";
+}
+print <<END
+</select>
+</td>
+<td width='5%'  align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day before'}' value='&lt;&lt;' /></td>
+<td width='5%'  align='center'><input type='submit' name='ACTION' title='$Lang::tr{'day after'}' value='&gt;&gt;' /></td>
+<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' /></td>
+<td width='10%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'export'}' /></td>
+</tr>
+</table>
+</form>
+END
+;
+
+&Header::closebox();
+
+&Header::openbox('100%', 'left', $Lang::tr{'log'});
+print "<p><b>$Lang::tr{'total hits for log section'} $date: $lines</b></p>";
+
+$start = $lines - ${Header::viewsize} if ($start >= $lines - ${Header::viewsize});
+$start = 0 if ($start < 0);
+
+my $prev;
+if ($start == 0) {
+	$prev = -1;
+} else {
+	$prev = $start - ${Header::viewsize};
+	$prev = 0 if ( $prev < 0);
+}
+
+my $next;
+if ($start == $lines - ${Header::viewsize}) {
+	$next = -1;
+} else {
+	$next = $start + ${Header::viewsize};
+	$next = $lines - ${Header::viewsize} if ($next >= $lines - ${Header::viewsize});
+}
+
+if ($logsettings{'LOGVIEW_REVERSE'} eq 'on') { @log = reverse @log; }
+if ($lines != 0) { &oldernewer(); }
+
+print <<END
+<table width='100%' class='tbl'>
+<tr>
+	<th width='15%' align='center' class='boldbase'><b>$Lang::tr{'time'}</b></th>
+	<th width='10%' align='center' class='boldbase'><b>PID</b></th>
+	<th width='75%'>&nbsp;</th>
+</tr>
+END
+;
+
+$lines = 0;
+foreach $_ (@log) {
+	/^ *([0-9]+):[0-9]{6}([0-9]{2}):([0-9]{2})([0-9]{2})([0-9]{2}\.[0-9]{3}) (.*)$/;
+	my $pid = $1;
+	my $day = $2;
+	$day =~ tr / /0/;
+	my $time = $cgiparams{'DAY'} ? "$3:$4:$5" : "$day/$3:$4:$5" ;
+	my $data = $6;
+	my $col="";
+
+	if ($lines % 2) {
+		print "<tr>";
+		$col="bgcolor='$color{'color20'}'"; 
+	} else {
+		print "<tr>";
+		$col="bgcolor='$color{'color22'}'"; 
+	}
+	print "<td $col>$time<td $col>$pid<td $col>" .&Header::cleanhtml ("$data", 'y') . "</td></tr>\n";
+	$lines++;
+}
+print "</table>";
+
+&oldernewer();
+
+&Header::closebox();
+
+&Header::closebigbox();
+
+&Header::closepage();
+
+sub oldernewer {
+	print <<END
+<table width='100%'>
+<tr>
+END
+	;
+
+	print "<td align='center' width='50%'>";
+	if ($prev != -1) {
+		print "<a href='/cgi-bin/logs.cgi/zabbix_agentd.dat?$prev,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'older'}</a>"; 
+	} else {
+		print "$Lang::tr{'older'}"; 
+	}
+	print "</td>\n";
+
+	print "<td align='center' width='50%'>";
+	if ($next >= 0) {
+		print "<a href='/cgi-bin/logs.cgi/zabbix_agentd.dat?$next,$cgiparams{'MONTH'},$cgiparams{'DAY'}'>$Lang::tr{'newer'}</a>"; 
+	} else {
+		print "$Lang::tr{'newer'}"; 
+	}
+	print "</td>\n";
+
+	print <<END
+</tr>
+</table>
+END
+	;
+}
diff --git a/lfs/zabbix_agentd b/lfs/zabbix_agentd
index 281bd9fa3..49b8440f8 100644
--- a/lfs/zabbix_agentd
+++ b/lfs/zabbix_agentd
@@ -139,6 +139,10 @@  $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 	-mkdir -pv /etc/logrotate.d
 	install -v -m 644 $(DIR_SRC)/config/zabbix_agentd/logrotate \
 		/etc/logrotate.d/zabbix_agentd
+	
+	# Install addon-specific language-files.
+	install -v -m 004 $(DIR_SRC)/config/zabbix_agentd/zabbix_agentd.*.pl \
+		/var/ipfire/addon-lang/
 
 	@rm -rf $(DIR_APP)
 	@$(POSTBUILD)
diff --git a/src/paks/zabbix_agentd/install.sh b/src/paks/zabbix_agentd/install.sh
index 80632d1ec..465ea7e8a 100644
--- a/src/paks/zabbix_agentd/install.sh
+++ b/src/paks/zabbix_agentd/install.sh
@@ -32,6 +32,7 @@  if ! getent passwd zabbix; then
 fi
 
 extract_files
+/usr/local/bin/update-lang-cache
 
 # Create symlinks for runlevel interaction.
 ln -sf ../init.d/zabbix_agentd /etc/rc.d/rc3.d/S65zabbix_agentd
diff --git a/src/paks/zabbix_agentd/uninstall.sh b/src/paks/zabbix_agentd/uninstall.sh
index edff3b818..4342384de 100644
--- a/src/paks/zabbix_agentd/uninstall.sh
+++ b/src/paks/zabbix_agentd/uninstall.sh
@@ -25,6 +25,7 @@ 
 stop_service ${NAME}
 make_backup ${NAME}
 remove_files
+/usr/local/bin/update-lang-cache
 
 # Remove init-scripts and symlinks
 rm -rfv /etc/rc.d/rc*.d/*zabbix_agentd
diff --git a/src/paks/zabbix_agentd/update.sh b/src/paks/zabbix_agentd/update.sh
index a41e72ab4..f01e32810 100644
--- a/src/paks/zabbix_agentd/update.sh
+++ b/src/paks/zabbix_agentd/update.sh
@@ -40,6 +40,9 @@  if [ -f /etc/sudoers.d/zabbix ]; then
 	fi
 fi
 
+# Fix permissions on /var/log/zabbix/* to allow GUI to read the logfiles.
+find /var/log/zabbix -perm 640 -exec chmod 644 \{\} \;
+
 extract_backup_includes
 ./uninstall.sh
 ./install.sh