2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-22 19:52:03 +00:00
2018-10-12 01:20:18 -04:00

732 lines
28 KiB
Perl

package LogParse;
# IBM(c) 2016 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; }
use lib "$::XCATROOT/probe/lib/perl";
use probe_global_constant;
use probe_utils;
use xCAT::NetworkUtils;
use strict;
use Data::Dumper;
use File::Path;
use File::Copy;
use Time::Local;
use File::Basename;
#------------------------------------------
=head3
Description:
The constructor of class 'LogParse'
Arguments:
Public attributes:
$self->{verbose}:scalar, Offer verbose information, used for handling feature logic
$self->{load_type}:scalar, $::MONITOR or $::REPLAY, used for distinguishing monitor and replay.
private attributes:
$self->{log_open_info}: reference of a hash, used to save the log file operating information.
$self->{current_ref_year}: scalar, the year information of current time. such as 2016. Used for log time parsing
$self->{current_ref_time}: scalar, the epoch format of current time, such as 1472437250. Used for log time parsing
$self->{debug}: Scalar, offer debug information, used for hanlde code logic, used by developer to debug function running
$self->{debuglogpath}: Scalar, the path of debug log files
$self->{debuglogfd}: File descriptor of debug log files
The structure of "log_open_info" hash is:
$self->{log_open_info}->{<logfileshortname>}{openfd} : The file descriptor of sepecific openning log file
$self->{log_open_info}->{<logfileshortname>}{rotate_file_list} : Array, all rotate file about related log file
$self->{log_open_info}->{<logfileshortname>}{openning_file_index} : scalar, the index of openning file in rotate_file_list
$self->{log_open_info}->{<logfileshortname>}{next_read_point} : scalar, the read point of one log file, used by 'seek' function
$self->{log_open_info}->{<logfileshortname>}{filetype} : scalar, the type of current log file, $::LOGTYPE_RSYSLOG or $::LOGTYPE_HTTP
$self->{log_open_info}->{<logfileshortname>}{next_start_time} : scalar, the next read time
Returns:
The instance of class
=cut
#------------------------------------------
sub new {
my @args = @_;
my $self = {};
my $class = shift;
$self->{verbose} = shift;
$self->{load_type} = shift;
my %log_open_info;
$self->{log_open_info} = \%log_open_info;
my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = localtime(time());
$self->{current_ref_year} = $year;
$self->{current_ref_time} = time();
$self->{debug} = 0;
if ($self->{debug}) {
my $logfiledir = "/tmp/xcatprobedebug/";
mkpath("$logfiledir") unless (-d "$logfiledir");
$self->{debuglogpath} = $logfiledir;
$self->{debuglogfd} = undef;
}
bless($self, ref($class) || $class);
return $self;
}
#------------------------------------------
=head3
Description:
Public functuon. Calculate the possible host name of current server in rsyslog files.
Arguments:
NULL
Returns:
A array which contains the possible host names of current server
Such as ("xxxxxx", "xxxxx.domain",....)
=cut
#------------------------------------------
sub obtain_candidate_mn_hostname_in_log {
my $self = shift;
my $svr_hostname_short = `hostname -s`;
chomp($svr_hostname_short);
my $svr_hostname_domain = `hostname -d`;
chomp($svr_hostname_domain);
my @candidate_svr_hostname_inlog;
push(@candidate_svr_hostname_inlog, $svr_hostname_short);
push(@candidate_svr_hostname_inlog, "$svr_hostname_short.$svr_hostname_domain");
if ($self->{debug}) {
my $tmpstr = join(" ", @candidate_svr_hostname_inlog);
probe_utils->send_msg("stdout", "d", "The candidate MN hostname(s) in log are $tmpstr");
}
return @candidate_svr_hostname_inlog;
}
#------------------------------------------
=head3
Description:
Public function. Specify the log files scope which will be scaned.
Arguments:
NULL
Returns:
A hash which save all candidate log file information
$candidate_log{<label>}{file}
$candidate_log{<label>}{type}
<label> : The short name of log file
file: The log file name, including full path
type: The valid types are $::LOGTYPE_HTTP and $::LOGTYPE_RSYSLOG, refer to 'probe_global_constant' for more information.
=cut
#------------------------------------------
sub obtain_log_file_list {
my $self = shift;
my %candidate_log;
my @loglist = ("/var/log/messages",
"/var/log/xcat/cluster.log",
"/var/log/xcat/computes.log",
"/var/log/syslog");
my @candidate_log_set;
foreach my $log (@loglist){
push @candidate_log_set, $log if (-e "$log");
}
my $filename;
foreach my $log (@candidate_log_set) {
$filename = basename($log);
$filename =~ s/(\w+)\.(\w+)/$1/g;
$candidate_log{$filename}{file} = $log;
$candidate_log{$filename}{type} = $::LOGTYPE_RSYSLOG;
}
my $httplog;
if (-e "/var/log/httpd/access_log") {
$httplog = "/var/log/httpd/access_log";
} elsif (-e "/var/log/apache2/access_log") {
$httplog = "/var/log/apache2/access_log";
} elsif (-e "/var/log/apache2/access.log") {
$httplog = "/var/log/apache2/access.log";
}
$candidate_log{http}{file} = $httplog;
$candidate_log{http}{type} = $::LOGTYPE_HTTP;
if ($self->{debug}) {
my $exist_log_file_list;
$exist_log_file_list .= "$candidate_log{$_}{file} " foreach (keys %candidate_log);
probe_utils->send_msg("stdout", "d", "The log files to be scaned are $exist_log_file_list");
}
return \%candidate_log;
}
#------------------------------------------
=head3
Description:
Public function. Obtian logs which belong to a specific second from candidate log files.
Arguments:
the_time_to_load:(input attribute) the specific second.
valid_one_second_log_set_ref: (output attribute) the space which save the vaild logs. A array of reference of hash.
Refer to fucnction "obtain_log_content" for the hash structure of one log.
Returns:
1: success
0: failed
=cut
#------------------------------------------
sub obtain_one_second_logs {
my $self = shift;
my $the_time_to_load = shift;
my $valid_one_second_log_set_ref = shift;
if ($self->{debug}) {
my $logfile = "$self->{debuglogpath}/obtain_one_second_logs.$the_time_to_load";
open($self->{debuglogfd}, "> $logfile");
}
#read log for the first time
#need to find vaild log files and load them
if (!%{ $self->{log_open_info} }) {
#obtain all exist log files in current server
#such as "/var/log/message, /var/log/xcat/cluster.log......."
my $candidate_log_ref = $self->obtain_log_file_list();
foreach my $loglabel (keys %$candidate_log_ref) {
#obtain all rotate log file for one kind of log
#such as "/var/log/message, /var/log/message-20160506, /var/log/message-20160507......."
my $rotate_file_list_ref = $self->obtain_rotate_log_list($candidate_log_ref->{$loglabel}{file});
#depending on target log time, find out should read from which rotate log file and which point of this log file
my $read_start_point_ref = $self->obtain_valid_log_start_point($the_time_to_load, $rotate_file_list_ref, $candidate_log_ref->{$loglabel}{type});
$self->{log_open_info}->{$loglabel}{rotate_file_list} = $rotate_file_list_ref;
$self->{log_open_info}->{$loglabel}{openning_file_index} = $read_start_point_ref->{log_index};
$self->{log_open_info}->{$loglabel}{next_read_point} = $read_start_point_ref->{log_start_point};
$self->{log_open_info}->{$loglabel}{filetype} = $candidate_log_ref->{$loglabel}{type};
}
}
if ($self->{debug}) {
$self->debuglogger("------------Dumper self->{log_open_info}---------------");
foreach my $loglabel (keys %{ $self->{log_open_info} }) {
$self->debuglogger("[$loglabel]");
my $rotate_file_list = join(" ", @{ $self->{log_open_info}->{$loglabel}{rotate_file_list} });
$self->debuglogger("rotate_file_list: $rotate_file_list");
$self->debuglogger("openning_file_index: $self->{log_open_info}->{$loglabel}{openning_file_index}");
$self->debuglogger("next_read_point: $self->{log_open_info}->{$loglabel}{next_read_point}");
$self->debuglogger("filetype: $self->{log_open_info}->{$loglabel}{type}");
$self->debuglogger("openfd: $self->{log_open_info}->{$loglabel}{openfd}");
}
$self->debuglogger("--------------------------------------------------------\n");
}
foreach my $loglabel (keys %{ $self->{log_open_info} }) {
my $fd;
if (!exists($self->{log_open_info}->{$loglabel}{openfd})) {
if (!open($fd, "$self->{log_open_info}->{$loglabel}{rotate_file_list}->[$self->{log_open_info}->{$loglabel}{openning_file_index}]")) {
print "[error] open $self->{log_open_info}->{$loglabel}{rotate_file_list}->[$self->{log_open_info}->{$loglabel}{openning_file_index}] failed\n";
return 1;
}
} else {
$fd = $self->{log_open_info}->{$loglabel}{openfd};
}
if ($fd) {
$self->debuglogger("[read $self->{log_open_info}->{$loglabel}{rotate_file_list}->[$self->{log_open_info}->{$loglabel}{openning_file_index}]]");
my $next_read_point = $self->{log_open_info}->{$loglabel}{next_read_point};
my $next_start_time = 0;
my $read_eof = 1;
my $i = 0;
for ($i = $self->{log_open_info}->{$loglabel}{openning_file_index} ; $i < @{ $self->{log_open_info}->{$loglabel}{rotate_file_list} } ; $i++) {
if ($i == $self->{log_open_info}->{$loglabel}{openning_file_index}) {
seek($fd, $next_read_point, 0);
} else {
open($fd, $self->{log_open_info}->{$loglabel}{rotate_file_list}->[$i]);
$next_read_point = 0;
}
while (<$fd>) {
chomp;
$self->debuglogger("[$loglabel]read: $_");
my $log_content_ref = $self->obtain_log_content($self->{log_open_info}->{$loglabel}{filetype}, $_);
#if read the log whoes time bigger than target time, stop to read
$self->debuglogger("\t$log_content_ref->{time} $the_time_to_load");
if ($log_content_ref->{time} > $the_time_to_load) {
$next_start_time = $log_content_ref->{time};
$read_eof = 0;
$self->debuglogger("\tlast");
last;
} else {
#if read the log whoes time is equal the target time, save it
push @$valid_one_second_log_set_ref, $log_content_ref;
#adjust the next read point to next line
my $len = length($_) + 1;
$next_read_point += $len;
$self->debuglogger("\tnext_read_point + $len");
}
}
if ($read_eof) {
#reach the end of current openning file, maybe there are vaild log in next rotate file,
#prepare to search next rotate file
close($fd);
$self->debuglogger("\tread_eof");
} else {
#have found all vaild log in current openning fd
$self->{log_open_info}->{$loglabel}{openfd} = $fd;
$self->{log_open_info}->{$loglabel}{openning_file_index} = $i;
$self->{log_open_info}->{$loglabel}{next_read_point} = $next_read_point;
$self->{log_open_info}->{$loglabel}{next_start_time} = $next_start_time;
$self->debuglogger("\tfound all vaild logs");
last;
}
} #end ratate_files loop
if ($i == @{ $self->{log_open_info}->{$loglabel}{rotate_file_list} } && $read_eof == 1) {
$self->{log_open_info}->{$loglabel}{openfd} = 0;
$self->{log_open_info}->{$loglabel}{next_start_time} = 9999999999;
$self->debuglogger("read out all rotate files");
}
} #end $fd
} #end log_open_info loop
#delete duplicate logs
$self->delete_duplicate_log($valid_one_second_log_set_ref);
if ($self->{debug}) {
close($self->{debuglogfd});
}
return 0;
}
#------------------------------------------
=head3
Description:
Private function. Depending on target log file name, obtain all related rotated log files.
For example, if the target file is '/var/log/messages', the function should return all rotated '/var/log/messages' files.
Such as '/var/log/messages-20160101', '/var/log/messages-20160102'.........
The all related log files should save into a array in order, the latest log file should be in the tail and the oldest one is in the head of array.
For example, the array should look like ("/var/log/messages-20160103", "/var/log/messages-20160104", "/var/log/messages-20160105", "/var/log/messages");
Finally, this function return the reference of the array.
Arguments:
file_name: (input attribute) the target log file name, including full path.
rotate_file_list_ref: (output attibute) the reference of the array which include all related log files name.
Returns:
0: success
1: failed
=cut
#------------------------------------------
sub obtain_rotate_log_list {
my $self = shift;
my $file_name = shift;
my @files = ();
my $file_path = dirname($file_name);
my @files_all = glob("$file_path/*");
my @files_grep = grep /$file_name.+\d$/, @files_all;
@files = sort { -M "$b" <=> -M "$a" } @files_grep;
push @files, $file_name;
return \@files;
}
#------------------------------------------
=head3
Description:
Private function. Depending on the reference start time. go through all rotate file list, find out where should start to read log.
I.e. start from which point of which log file.
Arguments:
start_time: (input attribute) the target start time.
rotate_file_list_ref: (input attibute) the reference of the array which include all related log files name.
log_type: (input attribute) The type of log file
Returns:
start_point: a hash which include the index of start file and the start point of the file
%start_point{log_index}: the index of start file in the rotate file list
%start_point{log_start_point}: where start to read log from. this value will be used by "seek" function
=cut
#------------------------------------------
sub obtain_valid_log_start_point {
my $self = shift;
my $start_time = shift;
my $rotate_file_list_ref = shift;
my $log_type = shift;
my %start_point;
my @files = @{$rotate_file_list_ref};
my $list_index = @files - 1;
my $fd;
my $file;
my $filetype;
my $line;
$start_point{log_index} = 0;
$start_point{log_start_point} = 0;
while (@files) {
$file = pop(@files);
$filetype = `file $file 2>&1`;
chomp($filetype);
if (!open($fd, "$file")) {
print "open $file failed\n";
$list_index--;
next;
}
if ($line = <$fd>) {
my %log_content = %{ $self->obtain_log_content($log_type, $line, 0) };
if ($start_time <= $log_content{time}) {
$list_index--;
next;
} else {
$start_point{log_index} = $list_index;
seek($fd, 0, 2);
my $tail = tell;
my $head = 0;
my $lasttail = $tail;
my $file_tail = $tail;
my $tmp_start_time = $start_time - 1;
my $historynum = 0;
while ($head <= $tail) {
my $middle = int(($tail - $head) / 2) + $head;
seek($fd, $middle, 0);
$line = <$fd>;
$middle += length($line);
last unless ($line = <$fd>);
my %log_content = %{ $self->obtain_log_content($log_type, $line, 0) };
if ($tmp_start_time == $log_content{time}) {
$historynum = $middle;
last;
} elsif ($tmp_start_time < $log_content{time}) {
$tail = $middle;
last if ($tail == $lasttail);
$lasttail = $tail;
} else {
$head = $middle;
}
}
$historynum = $head unless ($historynum);
while ($historynum < $file_tail) {
seek($fd, $historynum, 0);
$line = <$fd>;
my %log_content = %{ $self->obtain_log_content($log_type, $line, 0) };
if ($start_time <= $log_content{time}) {
last;
} elsif ($start_time > $log_content{time}) {
$historynum += length($line);
}
}
$start_point{log_start_point} = $historynum;
last;
}
}
}
return \%start_point;
}
#------------------------------------------
=head3
Description:
Convert one line original log which comes from log file to a hash.
Arguments:
log_type :(input attribute) valid log type are $::LOGTYPE_RSYSLOG and $::LOGTYPE_HTTP
original_log :(input attribute) one line log in real log file
Returns:
log_content_ref: (output attribute) the reference of a hash structure
The hash structure which contain log message is
%log_content
$log_content{time} : the timestamp of log, the format is epoch_seconds
$log_content{sender} : the sender of log
$log_content{label} : the label of log, such as $::LOGLABEL_DHCPD, $::LOGLABEL_TFTP.... refer to "probe_global_constant" for all kinds vaild labels
$log_content{msg} : the main message of log
=cut
#------------------------------------------
sub obtain_log_content {
my $self = shift;
my $log_type = shift;
my $original_log = shift;
my %log_content = ();
my @split_line = split(/\s+/, $original_log);
if ($log_type == $::LOGTYPE_RSYSLOG) {
if ($split_line[0] =~ /(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)(.+)-(.+)/) {
$log_content{time_record} = "$4:$5:$6";
$log_content{time} = $self->convert_to_epoch_seconds($split_line[0]);
if (!xCAT::NetworkUtils->isIpaddr($split_line[1])) {
my @sender_tmp = split(/\./, $split_line[1]);
$log_content{sender} = $sender_tmp[0];
} else {
$log_content{sender} = $split_line[1];
}
if ($split_line[2] =~ /dhcpd/i) {
$log_content{label} = $::LOGLABEL_DHCPD;
} elsif ($split_line[2] =~ /in.tftpd/i) {
$log_content{label} = $::LOGLABEL_TFTP;
} elsif ($split_line[2] =~ /^xcat.genesis.doxcat/i or $split_line[3] =~ /^xcat.genesis.doxcat/i) {
$log_content{label} = $::LOGLABEL_DOXCAT;
} elsif ($split_line[2] =~ /^xcat.genesis.dodiscovery/i or $split_line[3] =~ /^xcat.genesis.dodiscovery/i) {
$log_content{label} = $::LOGLABEL_DISCOVERY;
} elsif ($split_line[2] =~ /^xcat/i) {
$log_content{label} = $::LOGLABEL_XCAT;
} else {
$log_content{label} = $::LOGLABEL_UNDEF;
}
if ($split_line[3] =~ /^xcat.genesis.doxcat/i or $split_line[3] =~ /^xcat.genesis.dodiscovery/i) {
$log_content{msg} = join(" ", @split_line[ 4 .. @split_line - 1 ]);
} else {
$log_content{msg} = join(" ", @split_line[ 3 .. @split_line - 1 ]);
}
} else {
my $timestamp = join(" ", @split_line[ 0 .. 2 ]);
$log_content{time_record} = $split_line[2];
$log_content{time} = $self->convert_to_epoch_seconds($timestamp);
if (!xCAT::NetworkUtils->isIpaddr($split_line[3])) {
my @sender_tmp = split(/\./, $split_line[3]);
$log_content{sender} = $sender_tmp[0];
} else {
$log_content{sender} = $split_line[3];
}
if ($split_line[4] =~ /dhcpd/i) {
$log_content{label} = $::LOGLABEL_DHCPD;
} elsif ($split_line[4] =~ /in.tftpd/i) {
$log_content{label} = $::LOGLABEL_TFTP;
} elsif ($split_line[4] =~ /^xcat.genesis.doxcat/i or $split_line[5] =~ /^xcat.genesis.doxcat/i) {
$log_content{label} = $::LOGLABEL_DOXCAT;
} elsif ($split_line[4] =~ /^xcat.genesis.dodiscovery/i or $split_line[5] =~ /^xcat.genesis.dodiscovery/i) {
$log_content{label} = $::LOGLABEL_DISCOVERY;
} elsif ($split_line[4] =~ /^xcat/i or $split_line[5] =~ /^xcat/i) {
$log_content{label} = $::LOGLABEL_XCAT;
} else {
$log_content{label} = $::LOGLABEL_UNDEF;
}
if ($split_line[5] =~ /^xcat.genesis.doxcat/i or $split_line[5] =~ /^xcat.genesis.dodiscovery/i) {
$log_content{msg} = join(" ", @split_line[ 6 .. @split_line - 1 ]);
} else {
$log_content{msg} = join(" ", @split_line[ 5 .. @split_line - 1 ]);
}
}
} elsif ($log_type == $::LOGTYPE_HTTP) {
$split_line[3] =~ s/^\[(.+)/$1/g;
if ($split_line[3] =~ /(\d+)\/(\w+)\/(\d+):(\d+):(\d+):(\d+)/) {
$log_content{time_record} = "$4:$5:$6";
}
$log_content{time} = $self->convert_to_epoch_seconds($split_line[3]);
if (!xCAT::NetworkUtils->isIpaddr($split_line[0])) {
my @sender_tmp = split(/\./, $split_line[0]);
$log_content{sender} = $sender_tmp[0];
} else {
$log_content{sender} = $split_line[0];
}
$log_content{label} = $::LOGLABEL_HTTP;
$log_content{msg} = join(" ", @split_line[ 5 .. @split_line - 1 ]);
}
return \%log_content;
}
#------------------------------------------
=head3
Description:
Convert input time format to the number of non-leap seconds since whatever time the system considers to be the epoch
Arguments:
timestr: the time format need to be converted
Returns:
the number of non-leap seconds since whatever time the system considers to be the epoch
=cut
#------------------------------------------
sub convert_to_epoch_seconds {
my $self = shift;
my $timestr = shift;
my $yday;
my $mday;
my $dday;
my $h;
my $m;
my $s;
my $epoch_seconds = -1;
my %monthsmap = ("Jan" => 0, "Feb" => 1, "Mar" => 2, "Apr" => 3, "May" => 4, "Jun" => 5, "Jul" => 6, "Aug" => 7, "Sep" => 8, "Oct" => 9, "Nov" => 10, "Dec" => 11);
# The time format looks like "2016-08-29T03:30:18.259287-04:00"
if ($timestr =~ /(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)(.+)-(.+)/) {
($yday, $mday, $dday, $h, $m, $s) = ($1 + 0, $2 - 1, $3 + 0, $4 + 0, $5 + 0, $6 + 0);
$epoch_seconds = timelocal($s, $m, $h, $dday, $mday, $yday);
# The time format looks like "Aug 15 02:43:31"
} elsif ($timestr =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)/) {
($mday, $dday, $h, $m, $s) = ($1, $2, $3, $4, $5);
$yday = $self->{current_ref_year};
$epoch_seconds = timelocal($s, $m, $h, $dday, $monthsmap{$mday}, $yday);
if ($self->{load_type} == $::MONITOR) {
if ($epoch_seconds < $self->{current_ref_time}) {
++$yday;
$epoch_seconds = timelocal($s, $m, $h, $dday, $monthsmap{$mday}, $yday);
}
} else {
if ($epoch_seconds > $self->{current_ref_time}) {
--$yday;
$epoch_seconds = timelocal($s, $m, $h, $dday, $monthsmap{$mday}, $yday);
}
}
# The time format looks like "15/Aug/2016:01:10:24"
} elsif ($timestr =~ /(\d+)\/(\w+)\/(\d+):(\d+):(\d+):(\d+)/) {
$epoch_seconds = timelocal($6, $5, $4, $1, $monthsmap{$2}, $3);
}
return $epoch_seconds;
}
#------------------------------------------
=head3
Description:
Private function. After obtain one second logs. deleted these duplicate logs.
Arguments:
vaild_log_set_ref:(input/output attribute) The reference of the log set which will be scaned to delete duplicate log
Returns:
NULL
=cut
#------------------------------------------
sub delete_duplicate_log {
my $self = shift;
my $vaild_log_set_ref = shift;
my $log_index = @$vaild_log_set_ref - 1;
my @delete_index;
for (my $i = $log_index ; $i > 0 ; $i--) {
for (my $j = 0 ; $j < $i ; $j++) {
if (($vaild_log_set_ref->[$i]->{time} == $vaild_log_set_ref->[$j]->{time}) &&
($vaild_log_set_ref->[$i]->{label} == $vaild_log_set_ref->[$j]->{label}) &&
($vaild_log_set_ref->[$i]->{sender} eq $vaild_log_set_ref->[$j]->{sender}) &&
($vaild_log_set_ref->[$i]->{msg} eq $vaild_log_set_ref->[$j]->{msg})) {
if (!grep { $_ eq $i } @delete_index) {
push @delete_index, $i;
last;
}
}
}
}
foreach (@delete_index) {
my @new_list = ();
splice(@$vaild_log_set_ref, $_, 1, @new_list);
}
if ($self->{debug}) {
$self->debuglogger("------------After delete duplicate logs---------------");
foreach my $log_ref (@{$vaild_log_set_ref}) {
$self->debuglogger("$log_ref->{msg}");
}
}
}
#------------------------------------------
=head3
Description:
Public function. Obtain the next second when should get logs from
Arguments:
NULL
Returns:
The second when should get logs from
=cut
#------------------------------------------
sub obtain_next_second {
my $self = shift;
my $next_start_time = 9999999999;
foreach my $loglabel (keys %{ $self->{log_open_info} }) {
if ($self->{log_open_info}->{$loglabel}{next_start_time} < $next_start_time) {
$next_start_time = $self->{log_open_info}->{$loglabel}{next_start_time};
}
}
return $next_start_time;
}
#------------------------------------------
=head3
Description:
The destructor of class 'LogParse'
Arguments:
NULL
Returns:
NULL
=cut
#------------------------------------------
sub destory {
my $self = shift;
foreach my $loglabel (keys %{ $self->{log_open_info} }) {
if ($self->{log_open_info}->{$loglabel}{openfd}) {
close($self->{log_open_info}->{$loglabel}{openfd});
}
}
if ($self->{debuglogfd}) {
close($self->{debuglogfd});
}
}
#------------------------------------------
=head3
Description:
Private function. Used for log debug information to disk.
Arguments:
$msg : The massage which will be logged into log file.
Returns:
NULL
=cut
#------------------------------------------
sub debuglogger {
my $self = shift;
my $msg = shift;
if ($self->{debug}) {
print {$self->{debuglogfd}} "$msg\n";
}
}
1;