#!/usr/bin/perl ############################################################################### # # Copyright (c) 2012 Ramon Novoa # Copyright (c) 2012 Artica Soluciones Tecnologicas S.L. # # grep_log_module Perl script to search log files for a matching pattern. The # last searched position is saved in an index file so that # consecutive runs do not return the same results. The log file # inode number is also saved to detect log rotation. # # 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; version 2 of the License. # # 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. # ############################################################################### use strict; use File::Basename; # Output format (module or log_module). my $Output = 'log_module'; # Be verbose my $Verbose = 0; # Index file storage directory, with a trailing '/' my $Idx_dir='/tmp/'; # Log file my $Log_file = ''; # Module name my $Module_name = "default_log"; # Index file my $Idx_file = ''; # Log file position index my $Idx_pos = 0; # Log file inode number my $Idx_ino = ''; # Log file size my $Idx_size = 0; # Regular expression to be matched my $Reg_exp = ''; ############################################################################### # SUB error_msg # Print an error message and exit. ############################################################################### sub error_msg ($) { my $err_msg = $_[0]; if (! -z $err_msg) { print(stderr "[error] $err_msg.\n"); } exit 1; } ############################################################################### # SUB print_help # Print a help message. ############################################################################### sub print_help () { print "Usage: $0 \n"; } ############################################################################### # SUB log_msg # Print a log message. ############################################################################### sub log_msg ($) { my $log_msg = $_[0]; if (! -z $log_msg && $Verbose == 1) { print(stdout "[log] $log_msg.\n"); } } ############################################################################### # SUB load_idx # Load index file. ############################################################################### sub load_idx () { my $line; my $current_ino; my $current_size; log_msg("Loading index file $Idx_file"); open(IDXFILE, $Idx_file) || error_msg("Error opening file $Idx_file: " . $!); # Read position and date $line = ; ($Idx_pos, $Idx_ino, $Idx_size) = split(' ', $line); close(IDXFILE); # Reset the file index if the file has changed $current_ino = (stat($Log_file))[1]; $current_size = -s "$Log_file"; if ($current_ino != $Idx_ino || $current_size < $Idx_size) { log_msg("File changed, resetting index"); $Idx_pos = 0; $Idx_ino = $current_ino; } $Idx_size = $current_size; return; } ############################################################################### # SUB save_idx # Save index file. ############################################################################### sub save_idx () { log_msg("Saving index file $Idx_file"); open(IDXFILE, "> $Idx_file") || error_msg("Error opening file $Idx_file: " . $!); print (IDXFILE $Idx_pos . " " . $Idx_ino . " " . $Idx_size); close(IDXFILE); return; } ############################################################################### # SUB create_idx # Create index file. ############################################################################### sub create_idx () { my $first_line; log_msg("Creating index file $Idx_file"); open(LOGFILE, $Log_file) || error_msg("Error opening file $Log_file: " . $!); # Go to EOF and save the position seek(LOGFILE, 0, 2); $Idx_pos = tell(LOGFILE); close(LOGFILE); # Save the file inode number $Idx_ino = (stat($Log_file))[1]; # Save the index file save_idx(); return; } ############################################################################### # SUB parse_log # Parse log file starting from position $Idx_pos. ############################################################################### sub parse_log () { my $line; log_msg("Parsing log file $Log_file"); # Open log file for reading open(LOGFILE, $Log_file) || error_msg("Error opening file $Log_file: " . $!); # Go to starting position. seek(LOGFILE, $Idx_pos, 0); # Parse log file my @data; while ($line = ) { if ($line =~ m/$Reg_exp/i) { push (@data, $line); } } $Idx_pos = tell(LOGFILE); close(LOGFILE); # Save the index file save_idx(); return @data; } ############################################################################### # SUB parse_log # Print log data to stdout. ############################################################################### sub print_log (@) { my @data = @_; # No data if ($#data < 0) { return; } # Log module if ($Output eq 'log_module') { my $output = "\n"; $output .= "\n"; $output .= ""; $output .= "\n"; print stdout $output; } # Regular module else { my $output = "\n"; $output .= "\n"; $output .= "\n"; $output .= "\n"; foreach my $line (@data) { $line =~ s/\]\]/]]]]>\n"; } $output .= "\n"; $output .= "\n"; print stdout $output; } } ############################################################################### ############################################################################### ## Main ############################################################################### ############################################################################### # Check command line parameters if ($#ARGV != 2) { print_help(); exit 1; } $Log_file = $ARGV[0]; $Module_name = $ARGV[1]; $Reg_exp = $ARGV[2]; # Create index file storage directory if ( ! -d $Idx_dir) { mkdir($Idx_dir) || error_msg("Error creating directory $Idx_dir: " . $!); } # Check that log file exists if (! -e $Log_file) { error_msg("File $Log_file does not exist"); } # Create index file if it does not exist $Idx_file=$Idx_dir . $Module_name . "_" . basename($Log_file) . ".idx"; if (! -e $Idx_file) { create_idx(); exit 0; } # Load index file load_idx(); # Parse log file my @data = parse_log(); # Print output to stdout print_log (@data); exit 0;