initial commit of file from CVS for e-smith-viewlogfiles on Wed 12 Jul 09:12:02 BST 2023
This commit is contained in:
@@ -0,0 +1 @@
|
||||
view
|
@@ -0,0 +1 @@
|
||||
configuration
|
0
root/etc/e-smith/events/e-smith-viewlogfiles-update/.gitignore
vendored
Normal file
0
root/etc/e-smith/events/e-smith-viewlogfiles-update/.gitignore
vendored
Normal file
127
root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/viewlogfiles
Executable file
127
root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/viewlogfiles
Executable file
@@ -0,0 +1,127 @@
|
||||
<!-- vim: ft=xml ts=8 sw=4 noet:
|
||||
-->
|
||||
<lexicon lang="en-us">
|
||||
<entry>
|
||||
<base>View log files</base>
|
||||
<trans>View log files</trans>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<base>FIRSTPAGE_DESC</base>
|
||||
<trans>
|
||||
<![CDATA[
|
||||
This panel allows you to view or download the log files generated
|
||||
by the services running on your server.
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>LOG_FILE_SELECT_DESC</base>
|
||||
<trans>Choose a log file to view</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>FILTER_PATTERN_DESC</base>
|
||||
<trans>
|
||||
<![CDATA[
|
||||
<p>You may optionally specify a filter pattern to display only the
|
||||
lines from the log file which match this pattern. If you leave
|
||||
this field blank, all available lines of the log file will be
|
||||
displayed. Note that this option is not used if you download the
|
||||
logfile.</p>
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>FILTER_PATTERN_LABEL</base>
|
||||
<trans>Filter Pattern (optional)</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>MATCH_PATTERN_DESC</base>
|
||||
<trans>
|
||||
<![CDATA[
|
||||
<p>You may also optionally specify a highlight pattern to mark in bold
|
||||
any lines from the log file which match the highlight pattern. The
|
||||
highlight pattern is applied to any lines which have already
|
||||
matched the filter pattern. Note that this option is not used if
|
||||
you download the logfile.</p>
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>MATCH_PATTERN_LABEL</base>
|
||||
<trans>Highlight Pattern (optional)</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>END_DESC</base>
|
||||
<trans>
|
||||
Please note that it may take quite some time to generate these
|
||||
reports.
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>VIEW</base>
|
||||
<trans>View log file</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>LOG_FILE_EMPTY</base>
|
||||
<trans>Log file "{$filename}" is empty!</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>VIEWING_TIME</base>
|
||||
<trans>Viewed at {$time}.</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>MATCH_HEADER</base>
|
||||
<trans>Displaying lines matching: "{$matchPattern}".</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>HIGHLIGHT_HEADER</base>
|
||||
<trans>Highlighting lines matching: "{$highlightPattern}".</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>NO_MATCHING_LINES</base>
|
||||
<trans>No matching lines displayed.</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>FILENAME_ERROR</base>
|
||||
<trans>
|
||||
<![CDATA[
|
||||
<p>Error while specifying log file name.</p>
|
||||
<p>Invalid report type "{$filename}".</p>
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>REFRESH</base>
|
||||
<trans>Refresh this logfile</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>OP_DESC</base>
|
||||
<trans><![CDATA[
|
||||
<p>You must choose between viewing the logfile in your browser, or
|
||||
downloading the logfile to your computer. If the logfile is
|
||||
particularly large, you may wish to download it instead of
|
||||
attempting to open it in your browser, as this is a problem for
|
||||
some web browsers.</p>
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>OP_LABEL</base>
|
||||
<trans>Operation</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>DOWNLOAD_PAGE_DESC</base>
|
||||
<trans><![CDATA[
|
||||
<p>Your logfile download is now prepared. It will proceed as soon
|
||||
as you click on the "Next" button below, and instruct
|
||||
your browser to accept the download via the pop-up window that
|
||||
will appear.</p>
|
||||
]]>
|
||||
</trans>
|
||||
</entry>
|
||||
<entry>
|
||||
<base>DOWNLOAD_FILE</base>
|
||||
<trans>Preparing to download the logfile {$logfile}.</trans>
|
||||
</entry>
|
||||
</lexicon>
|
477
root/etc/e-smith/web/functions/viewlogfiles
Executable file
477
root/etc/e-smith/web/functions/viewlogfiles
Executable file
@@ -0,0 +1,477 @@
|
||||
#! /usr/bin/perl -wT
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# heading : Administration
|
||||
# description : View log files
|
||||
# navigation : 4000 4400
|
||||
#
|
||||
# $Id: viewlogfiles,v 1.31 2005/08/25 21:08:41 charlieb Exp $
|
||||
#----------------------------------------------------------------------
|
||||
# copyright (C) 1999-2007 Mitel Networks Corporation
|
||||
#
|
||||
# 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 2 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
#----------------------------------------------------------------------
|
||||
use strict;
|
||||
use esmith::FormMagick;
|
||||
|
||||
use esmith::ConfigDB;
|
||||
use esmith::cgi;
|
||||
use Time::TAI64;
|
||||
use File::Basename;
|
||||
use HTML::Entities;
|
||||
use CGI;
|
||||
|
||||
use constant TRUE => 1;
|
||||
use constant FALSE => 0;
|
||||
|
||||
my $viewlogfiles = esmith::ConfigDB->open->get('viewlogfiles');
|
||||
|
||||
my $fm = esmith::FormMagick->new();
|
||||
|
||||
my $q = CGI->new();
|
||||
|
||||
# Save this operation preference for later.
|
||||
my $operation = $q->param('operation');
|
||||
$viewlogfiles->merge_props('DefaultOperation', $operation)
|
||||
if $operation;
|
||||
|
||||
if ($operation and $operation eq 'download')
|
||||
{
|
||||
perform_download($fm, $q);
|
||||
}
|
||||
else
|
||||
{
|
||||
#$fm->debug(1);
|
||||
$fm->display();
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
viewlogfiles -- An interface to system log files, allowing for pattern
|
||||
filtering and highlighting.
|
||||
|
||||
=head2 DESCRIPTION
|
||||
|
||||
This screen allows the administrator to flexibly view various system log files.
|
||||
|
||||
=begin testing
|
||||
|
||||
use esmith::FormMagick::Tester;
|
||||
use esmith::TestUtils;
|
||||
use esmith::ConfigDB;
|
||||
use esmith::AccountsDB;
|
||||
|
||||
my $panel = $Original_File;
|
||||
my $ua = esmith::FormMagick::Tester->new();
|
||||
|
||||
my $c = esmith::ConfigDB->open();
|
||||
my $a = esmith::AccountsDB->open();
|
||||
|
||||
is (mode($panel), '4755', "Check permissions on script");
|
||||
ok ($ua->get_panel($panel), "ABOUT TO RUN L10N TESTS");
|
||||
is ($ua->{status}, 200, "200 OK");
|
||||
ok ($ua->set_language("en-us"), "Set language to English");
|
||||
ok ($ua->get_panel($panel), "Get panel");
|
||||
is ($ua->{status}, 200, "200 OK");
|
||||
like($ua->{content}, qr/View log files/, "Saw translated form title");
|
||||
|
||||
# View the messages log:
|
||||
|
||||
$ua->field("filename" => "messages");
|
||||
$ua->field(highlightPattern => "");
|
||||
$ua->field(matchPattern => "");
|
||||
ok ($ua->click("View log file"), "Click View log file");
|
||||
is ($ua->{status}, 200, "200 OK");
|
||||
like($ua->{content}, qr/Viewed at/, "Saw validation messages");
|
||||
|
||||
# View the messages log and filter all output:
|
||||
|
||||
ok ($ua->get_panel($panel), "Get panel");
|
||||
$ua->field("filename" => "messages");
|
||||
$ua->field(highlightPattern => "gibberish-gibberish");
|
||||
$ua->field(matchPattern => "gibberish-gibberish");
|
||||
ok ($ua->click("View log file"), "Click View log file");
|
||||
is ($ua->{status}, 200, "200 OK");
|
||||
like($ua->{content}, qr/No matching lines/, "Saw validation messages");
|
||||
|
||||
=end testing
|
||||
|
||||
=cut
|
||||
|
||||
#------------------------------------------------------------
|
||||
# subroutine to display initial form
|
||||
#------------------------------------------------------------
|
||||
|
||||
our %logfiles = ();
|
||||
|
||||
sub timestamp2local
|
||||
{
|
||||
$_ = shift;
|
||||
if (/^(\@[0-9a-f]{24})(.*)/s)
|
||||
{
|
||||
return Time::TAI64::tai64nlocal($1) . $2;
|
||||
}
|
||||
elsif (/^([0-9]{10}\.[0-9]{3})(.*)/s)
|
||||
{
|
||||
return localtime($1) . $2;
|
||||
}
|
||||
return $_;
|
||||
}
|
||||
|
||||
sub findlogFiles
|
||||
{
|
||||
my $fm = shift;
|
||||
my $q = $fm->{cgi};
|
||||
|
||||
use File::Find;
|
||||
sub findlogfiles
|
||||
{
|
||||
my $path = $File::Find::name;
|
||||
|
||||
if (-f)
|
||||
{
|
||||
# Remove leading /var/log/messages
|
||||
$path =~ s:^/var/log/::;
|
||||
# don't bother to collect files known to be non-text
|
||||
# or not log files
|
||||
foreach (qw(
|
||||
lastlog
|
||||
btmp$
|
||||
wtmp
|
||||
lock
|
||||
(?<!qpsmtpd/)state
|
||||
httpd/ssl_mutex.\d*
|
||||
httpd/ssl_scache.pag
|
||||
httpd/ssl_scache.dir
|
||||
\/config$
|
||||
))
|
||||
{
|
||||
return if $path =~ /$_/;
|
||||
}
|
||||
|
||||
my ($file_base, $file_path, $file_type) = fileparse($path);
|
||||
|
||||
if ( $file_base =~ /@.*/ )
|
||||
{
|
||||
$logfiles{$path} = $file_path . timestamp2local($file_base);
|
||||
}
|
||||
else
|
||||
{
|
||||
$logfiles{$path} = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Now go and find all the files under /var/log
|
||||
find({wanted => \&findlogfiles, no_chdir => 1}, '/var/log');
|
||||
|
||||
return \%logfiles;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# subroutine to perform actions and display result
|
||||
#------------------------------------------------------------
|
||||
|
||||
sub performAndShowResult ($)
|
||||
{
|
||||
my $fm = shift;
|
||||
my $q = $fm->{cgi};
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Verify the arguments and untaint the variables (see Camel
|
||||
# book, "Detecting and laundering tainted data", pg. 358)
|
||||
#------------------------------------------------------------
|
||||
my $filename = $q->param ('filename');
|
||||
if ($filename =~ /^([\S\s]+)$/)
|
||||
{
|
||||
$filename = $1;
|
||||
}
|
||||
elsif ($filename =~ /^$/)
|
||||
{
|
||||
$filename = "messages";
|
||||
}
|
||||
else
|
||||
{
|
||||
print $fm->localise("FILENAME_ERROR", { filename => "$filename" } );
|
||||
return;
|
||||
}
|
||||
my $matchPattern = $q->param ('matchPattern');
|
||||
if ($matchPattern =~ /^(\S+)$/)
|
||||
{
|
||||
$matchPattern = $1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$matchPattern = ".";
|
||||
}
|
||||
my $highlightPattern = $q->param ('highlightPattern');
|
||||
if ($highlightPattern =~ /^(\S+)$/)
|
||||
{
|
||||
$highlightPattern = $1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$highlightPattern = '';
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Looks good; go ahead and generate the report.
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $fullpath = "/var/log/$filename";
|
||||
|
||||
if (-z $fullpath)
|
||||
{
|
||||
print $fm->localise("LOG_FILE_EMPTY", { filename => "$filename" } );
|
||||
return;
|
||||
}
|
||||
|
||||
print "$fullpath: \n";
|
||||
|
||||
print $fm->localise("VIEWING_TIME",
|
||||
{ time => $fm->gen_locale_date_string() } );
|
||||
|
||||
unless ( $matchPattern eq '.' )
|
||||
{
|
||||
print "<p>\n";
|
||||
print $fm->localise("MATCH_HEADER", { matchPattern => "$matchPattern" } );
|
||||
}
|
||||
|
||||
if ( $highlightPattern )
|
||||
{
|
||||
print "<p>\n";
|
||||
print $fm->localise("HIGHLIGHT_HEADER", { highlightPattern => "$highlightPattern" } );
|
||||
}
|
||||
|
||||
if ($filename =~ /\.gz$/)
|
||||
{
|
||||
my $pid = open(LOGFILE, "-|");
|
||||
die "Couldn't fork: $!" unless defined $pid;
|
||||
unless ($pid)
|
||||
{
|
||||
# Child
|
||||
exec("/bin/zcat", $fullpath)
|
||||
|| die "Can't exec zcat: $!";
|
||||
# NOTREACHED
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
open(LOGFILE, "$fullpath");
|
||||
}
|
||||
|
||||
my $somethingMatched = 0;
|
||||
my $fileEmpty = 1;
|
||||
print "<PRE>";
|
||||
while(<LOGFILE>)
|
||||
{
|
||||
$fileEmpty = 0;
|
||||
next unless /$matchPattern/;
|
||||
$somethingMatched = 1;
|
||||
|
||||
$_ = timestamp2local($_);
|
||||
$_ = HTML::Entities::encode_entities($_);
|
||||
($highlightPattern && /$highlightPattern/)
|
||||
? print "<b>$_</b>"
|
||||
: print;
|
||||
}
|
||||
print "</PRE>";
|
||||
|
||||
if ($fileEmpty)
|
||||
{
|
||||
print "<p>\n";
|
||||
print $fm->localise("LOG_FILE_EMPTY");
|
||||
}
|
||||
else
|
||||
{
|
||||
unless ($somethingMatched)
|
||||
{
|
||||
print "<p>\n";
|
||||
print $fm->localise("NO_MATCHING_LINES");
|
||||
}
|
||||
}
|
||||
|
||||
close LOGFILE;
|
||||
print $q->table({-width => '100%'},
|
||||
$q->Tr($q->th({-class => 'sme-layout'},
|
||||
$q->a( { -href => "viewlogfiles?page=0&Next=viewLog" .
|
||||
"&filename=$filename&matchPattern=$matchPattern" .
|
||||
"&highlightPattern=$highlightPattern" .
|
||||
"&operation=view",
|
||||
-class => 'button-like'},
|
||||
$fm->localise('REFRESH')))));
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_viewlog_buttons
|
||||
{
|
||||
my $self = shift;
|
||||
my $q = $self->{cgi};
|
||||
my $filename = $q->param('filename');
|
||||
my $matchPattern = $q->param('matchPattern');
|
||||
my $highlightPattern = $q->param('highlightPattern');
|
||||
|
||||
print $q->table({-width => '100%'},
|
||||
$q->Tr({-valign => 'center'},
|
||||
$q->th({-class => 'sme-layout', -valign => 'center'},
|
||||
$q->a( { -href => "viewlogfiles?page=0&Next=viewLog" .
|
||||
"&filename=$filename&matchPattern=$matchPattern" .
|
||||
"&highlightPattern=$highlightPattern" .
|
||||
"&skip_header=1",
|
||||
-class => 'button-like'},
|
||||
$self->localise('DOWNLOAD')),
|
||||
$q->submit( {-value => $self->localise('VIEW') } ))));
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub perform_download
|
||||
{
|
||||
my $fm = shift;
|
||||
my $q = shift;
|
||||
my $filename = $q->param("filename");
|
||||
my $fullpath = "/var/log/$filename";
|
||||
|
||||
# Save this information for later.
|
||||
my $operation = $q->param('operation');
|
||||
$viewlogfiles->merge_props('DefaultOperation', $operation);
|
||||
|
||||
# If the client is on windows, we must handle this a little differently.
|
||||
my $win32 = FALSE;
|
||||
my $mac = FALSE;
|
||||
my $agent = $ENV{HTTP_USER_AGENT} || "";
|
||||
if ($agent =~ /win32|windows/i)
|
||||
{
|
||||
$win32 = TRUE;
|
||||
}
|
||||
elsif ($agent =~ /mac/i)
|
||||
{
|
||||
$mac = TRUE;
|
||||
}
|
||||
|
||||
# Check for errors first. Once we start sending the file it's too late to
|
||||
# report them.
|
||||
my $error = "";
|
||||
unless (-f $fullpath)
|
||||
{
|
||||
$error = $fm->localise("ERR_NOEXIST_FILE");
|
||||
}
|
||||
local *FILE;
|
||||
open(FILE, "<$fullpath")
|
||||
or $error = $fm->localise("ERR_NOOPEN_FILE");
|
||||
# Put other error checking here.
|
||||
if ($error)
|
||||
{
|
||||
# FIXME: Add the header and footer template references here.
|
||||
print <<"EOF";
|
||||
Content-Type: text/html
|
||||
|
||||
$error
|
||||
EOF
|
||||
return undef;
|
||||
}
|
||||
# Fix the filename, as it might have a directory prefixed to it.
|
||||
if ($filename =~ m#/#)
|
||||
{
|
||||
$filename = (split /\//, $filename)[-1];
|
||||
}
|
||||
|
||||
# Otherwise, send the file. Start with the headers.
|
||||
# Note: The Content-disposition must be attachment, or IE will view the
|
||||
# file inline like it's told. It ignores the Content-type, but it likes
|
||||
# the Content-disposition (an officially unsupported header) for some
|
||||
# reason. Yay Microsoft.
|
||||
print <<"EOF";
|
||||
Expires: 0
|
||||
Content-type: application/octet-stream
|
||||
Content-disposition: attachment; filename=$filename
|
||||
|
||||
EOF
|
||||
# And send the file.
|
||||
my $nl = "\n";
|
||||
if ($win32) { $nl = "\r\n" }
|
||||
elsif ($mac) { $nl = "\r" }
|
||||
while (my $line = <FILE>)
|
||||
{
|
||||
chomp $line;
|
||||
print timestamp2local($line) . $nl;
|
||||
}
|
||||
close(FILE);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub show_operation_widget
|
||||
{
|
||||
my $self = shift;
|
||||
my $q = $self->{cgi};
|
||||
my $description = $self->localise('OP_DESC');
|
||||
my $label = $self->localise('OP_LABEL');
|
||||
|
||||
my $defaultop = $viewlogfiles->prop('DefaultOperation');
|
||||
my $select = '<select name="operation" size="1">' . "\n";
|
||||
if ($defaultop eq 'view')
|
||||
{
|
||||
$select .= '<option value="view" selected>' .
|
||||
$self->localise("VIEW") . '</option>' . "\n";
|
||||
$select .= '<option value="download">' .
|
||||
$self->localise("DOWNLOAD") . '</option>' . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$select .= '<option value="view">' .
|
||||
$self->localise("VIEW") . '</option>' . "\n";
|
||||
$select .= '<option value="download" selected>' .
|
||||
$self->localise("DOWNLOAD") . '</option>' . "\n";
|
||||
}
|
||||
$select .= '</select>' . "\n";
|
||||
|
||||
print $q->Tr($q->td({-colspan => 2}, $description));
|
||||
print $q->Tr($q->td({-class => 'sme-noborders-label'}, $label),
|
||||
$q->td({-class => 'sme-noborders-content'}, $select));
|
||||
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
__DATA__
|
||||
<form title="View log files" header="/etc/e-smith/web/common/head.tmpl" footer="/etc/e-smith/web/common/foot.tmpl">
|
||||
<page name="Initial"
|
||||
pre-event="print_status_message()">
|
||||
<description>FIRSTPAGE_DESC</description>
|
||||
<field type="select" id="filename" options="findlogFiles()"
|
||||
value="messages">
|
||||
<label>LOG_FILE_SELECT_DESC</label>
|
||||
</field>
|
||||
<field type="text" id="matchPattern">
|
||||
<description>FILTER_PATTERN_DESC</description>
|
||||
<label>FILTER_PATTERN_LABEL</label>
|
||||
</field>
|
||||
<field type="text" id="highlightPattern">
|
||||
<description>MATCH_PATTERN_DESC</description>
|
||||
<label>MATCH_PATTERN_LABEL</label>
|
||||
</field>
|
||||
<subroutine src="show_operation_widget()" />
|
||||
<field type="literal">
|
||||
<description>END_DESC</description>
|
||||
</field>
|
||||
<subroutine src="print_button('NEXT')" />
|
||||
</page>
|
||||
<page name="viewLog" pre-event="turn_off_buttons()">
|
||||
<subroutine src="performAndShowResult()" />
|
||||
</page>
|
||||
</form>
|
Reference in New Issue
Block a user