package SrvMngr::Controller::Viewlogfiles; #---------------------------------------------------------------------- # heading : Investigation # description : View log files # navigation : 7000 100 # # # routes : end #---------------------------------------------------------------------- use strict; use warnings; use Mojo::Base 'Mojolicious::Controller'; #use esmith::FormMagick qw(gen_locale_date_string); use Locale::gettext; use SrvMngr::I18N; use SrvMngr qw(theme_list init_session); use esmith::ConfigDB; use Time::TAI64; use File::Basename; use HTML::Entities; use esmith::FormMagick qw(gen_locale_date_string); use File::Temp qw(tempfile); use constant TRUE => 1; use constant FALSE => 0; our $cdb = esmith::ConfigDB->open() || die "Couldn't open config db"; our @logfiles = (); # with array sub main { my $c = shift; $c->app->log->info($c->log_req); my %log_datas = (); my $title = $c->l('log_FORM_TITLE'); my $notif = ''; $log_datas{default_op} = ($cdb->get('viewlogfiles')->prop('DefaultOperation')) || 'view'; $c->stash( title => $title, notif => $notif, log_datas => \%log_datas); $c->render(template => 'viewlogfiles'); }; sub do_action { my $c = shift; $c->app->log->info($c->log_req); my $title = $c->l('log_FORM_TITLE'); my $notif = ''; my $result = ""; my %log_datas = (); $log_datas{filename} = $c->param('Filename'); $log_datas{matchpattern} = $c->param('Matchpattern'); $log_datas{highlightpattern} = $c->param('Highlightpattern'); $log_datas{operation} = $c->param('Operation'); if ($log_datas{operation} eq 'download') { $log_datas{'trt'} = "DOWN" } else { $log_datas{'trt'} = "SHOW" } if ($log_datas{filename} =~ /^([\S\s]+)$/) { $log_datas{filename} = $1; } elsif ($log_datas{filename} =~ /^$/) { $log_datas{filename} = "messages"; } else { $result .= $c->l("log_FILENAME_ERROR", $log_datas{filename} ) . " "; } if ($log_datas{matchpattern} =~ /^(\S+)$/) { $log_datas{matchpattern} = $1; } else { $log_datas{matchpattern} = "."; } if ($log_datas{highlightpattern} =~ /^(\S+)$/) { $log_datas{highlightpattern} = $1; } else { $log_datas{highlightpattern} = ''; } my $fullpath = "/var/log/$log_datas{filename}"; if (-z $fullpath) { $result .= $c->l("log_LOG_FILE_EMPTY", "$log_datas{filename}" ); } if ($log_datas{trt} eq "SHOW") { if ( ! $result ) { $result = $c->render_to_string(inline => showlogFile( $c, %log_datas )); } if ( $result ) { $c->stash(title => $title, modul => $result, log_datas => \%log_datas); return $c->render(template => 'viewlogfiles2'); } } if ( $log_datas{trt} eq 'DOWN' ) { my $modul = 'Log file download'; $notif = download_logFile( $c, %log_datas ); return undef unless defined $notif; } $c->stash( title => $title, notif => $notif, log_datas => \%log_datas); $c->render(template => 'viewlogfiles'); }; 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 $c = shift; 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 (? \&findlogfiles, no_chdir => 1}, '/var/log'); my @logf = sort { $a->[0] cmp $b->[0] } @logfiles; return \@logf; } sub showlogFile { my ($c, %log_datas) = @_; my $fullpath = "/var/log/$log_datas{filename}"; my $out = ''; $out .= sprintf("$fullpath: \n"); $out .= sprintf($c->l("log_VIEWING_TIME", $c->gen_locale_date_string() )); unless ( $log_datas{matchpattern} eq '.' ) { #$out .= sprintf("
\n"); $out .= sprintf($c->l("log_MATCH_HEADER", $log_datas{matchpattern} )); } if ( $log_datas{highlightpattern} ) { #$out .= sprintf("
\n"); $out .= sprintf($c->l("log_HIGHLIGHT_HEADER", "$log_datas{highlightpattern}" )); } if ($log_datas{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; $out .= sprintf("
"); while("); if ($fileEmpty) { $out .= sprintf(") { $fileEmpty = 0; next unless /$log_datas{matchpattern}/; $somethingMatched = 1; $_ = timestamp2local($_); $_ = HTML::Entities::encode_entities($_); ($log_datas{highlightpattern} && /$log_datas{highlightpattern}/) ? $out .= sprintf( "$_" ) : $out .= sprintf("$_"); } $out .= sprintf("
\n"); $out .= sprintf($c->l("log_LOG_FILE_EMPTY")); } else { unless ($somethingMatched) { $out .= sprintf("
\n");
$out .= sprintf($c->l("log_NO_MATCHING_LINES"));
}
}
close LOGFILE;
return $out;
}
sub download_logFile {
my ($c, %log_datas) = @_;
my $fullpath = "/var/log/$log_datas{filename}";
# Save this information for later.
$cdb->get('viewlogfiles')->merge_props('DefaultOperation', $log_datas{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 = $c->l("log_ERR_NOEXIST_FILE") . $fullpath;
}
local *FILE;
open(FILE, "<$fullpath")
or $error = $c->l("log_ERR_NOOPEN_FILE");
# Put other error checking here.
return $error if $error;
# Fix the filename, as it might have a directory prefixed to it.
my $filename = $log_datas{filename};
if ( $filename =~ m#/# ) {
$filename = (split /\//, $filename)[-1];
}
# And send the file.
my $nl = "\n";
if ($win32) { $nl = "\r\n" }
elsif ($mac) { $nl = "\r" }
# 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.
my $file2 = new File::Temp( UNLINK => 0 );
while (my $line =