OpenWetWare:Software/Server/Urchin/Log Rotation/WebLogRotate


 * 1) !/usr/bin/perl -w
 * 2) RCS ID: $Revision: 1.7 $
 * 3) Script to rotate the specified logs and name them with yesterday's
 * 4) date.  The script also restarts the web server with a specified command.
 * 5) and optionally compresses old logs and removes them after a certain period.
 * 6) Copyright (c) 2002, 2003, 2004 Urchin Software Corporation
 * 7) Usage: weblog_rotate.pl [--log /path/to/log [--log /path/to/log] \
 * 8)                         | [--loglist /path/to/loglist]] \
 * 9)                         --touchlog \
 * 10)                         --restart_cmd "apachectl restart" \
 * 11)                         --compress --days N --help
 * 12)  Where:
 * 13)     --loglist specifies the path to a file containing the full pathnames
 * 14)       of all the logs that are to be rotated. This option cannot be used
 * 15)       with the --log option.
 * 16)     --log specifies the full path to the log file to be rotated
 * 17)       (multiple --log entries are allowed)
 * 18)     --touchlog specifies that a new log should be created once the
 * 19)       original log is rotated.
 * 20) 	(default is not to create the log)
 * 21)     --restart_cmd specifies the command to restart the web server
 * 22)       (default is apachectl restart)
 * 23)     --compress specifies whether or not to compress the logs with gzip
 * 24)       (default is off)
 * 25)     --noprune disables automatic pruning of archived logs
 * 26)       (default is off)
 * 27)     --days specifies how many days to keep archived logs
 * 28)       (default is 60, minimum value is 1)
 * 29)     --help shows this message\n\n";
 * 1)     --noprune disables automatic pruning of archived logs
 * 2)       (default is off)
 * 3)     --days specifies how many days to keep archived logs
 * 4)       (default is 60, minimum value is 1)
 * 5)     --help shows this message\n\n";

use strict; use Time::localtime; use Getopt::Long;

my @logs = ; my $loglistfile = ""; my $restart_cmd = "apachectl restart"; my $days = 60; my $compress = 0; my $noprune = 0; my $touchlog = 0; my $gstatus; my $abslogpath; my $help = 0;
 * 1) Initialize variables

$gstatus = GetOptions('loglist=s' => \$loglistfile, 'log=s' => \@logs, 'restart_cmd=s' => \$restart_cmd, 'noprune' => \$noprune, 'days=i' => \$days, 'touchlog' => \$touchlog, 'compress' => \$compress, 'help' => \$help); if ($help) { &Usage; exit; } if ($gstatus ne 1) { &Usage; exit(1); }
 * 1) Read in the options

if ( $loglistfile ne "" ) { if ( @logs ) { print "FATAL error: \"--log\" and \"--loglist\" options are mutually exclusive\n"; &Usage; exit(1); }	open(LOGLISTFILE, $loglistfile) || die "FATAL error: can't open log list file $loglistfile\n"; @logs = ; }

my $yesterday = convert_epoch(time - 86400);
 * 1) Calculate the date string for 'yesterday'

if ($days <= 0) { $days = 1; }
 * 1) Ensure that '$days' is at least 1

my $cutoff_date = convert_epoch(time - ($days * 86400));
 * 1) Calculate the date string for '$days' ago

my ($log, $new_log, $dir); my ($mode, $uid, $gid); foreach $log (@logs) { chomp($log); # Create the name for the new log $new_log = "$log.$yesterday";
 * 1) Rotate each log file inside its current directory

# Verify that $log exists and is readable if ((!-e $log) && (!-r $log)) { warn "Logfile: $log does not exist or is unreadable\n"; next; }

# Move $log to $new_log as long as it doesn't overwrite another file if ((-e $new_log) || ((-e "$new_log.gz") && $compress)) { warn "Logfile: $new_log already exists. Skipping rotation...\n"; } else { rename($log, $new_log) || warn "Unable to rename: $log to $new_log"; if ( $touchlog ) { ($mode,$uid,$gid) = (stat("$new_log"))[2,4,5]; open(LOG,"+>$log") || warn "Unable to create $log"; close(LOG); chown($uid,$gid,$log) || warn "Unable to change ownership/group of $log to UID $uid/GID $gid"; chmod($mode,$log) || warn "Unable to change permissions of $log to $mode"; }	} }

if ($restart_cmd) { system($restart_cmd) && warn "$restart_cmd failed to restart web server properly"; }
 * 1) Restart the web server

foreach $log (@logs) { # Create the name for the new log $new_log = "$log.$yesterday";
 * 1) Loop through logs and prune and/or gzip as necessary.

# Determine the directory where the log file is located $_ = $log; ($dir) = m#(^/.*/)#;

# Compress the logs if set as option if ($compress) { # Verify that $new_log exists and is readable and compress the log if ((!-e $new_log) && (!-r $new_log)) { warn "Cannot compress $new_log since it does not exist or is not readable"; next; } else { system("/usr/bin/gzip $new_log") && warn "Problems gzipping $new_log"; }	}

# Go to the next log if log pruning is disabled if ($noprune) { print "Skipping log pruning for $log\n"; next; }

# Remove outdated logs from the directory opendir(DIR, $dir) || warn "Unable to open archived logs directory: $dir"; while (my $file = readdir(DIR)) { $abslogpath = "$dir$file"; # Skip logs that don't match the same base logfile name if ( index($abslogpath,$log) == -1 ) { next; } # Skip remaining logs that don't have a YYYYMMDD suffix pattern if ($file =~ /(\d{8})/) { if ($1 < $cutoff_date) { unlink("$dir$file") || warn "Problems removing file: $dir$file"; }		}	} }

sub convert_epoch { my $rawtime = $_[0]; my $formatedtime = ""; if ((! defined($rawtime)) || $rawtime eq "") { $formatedtime = 0; } else { $rawtime = localtime($rawtime); $formatedtime = sprintf("%04d%02d%02d", $rawtime->year+1900, $rawtime->mon+1, $rawtime->mday); }	return($formatedtime); }
 * 1) Subroutine to show the usage of this script

sub Usage { print "Usage: $0 [--loglist /path/to/loglist || --log /path/to/log [--log /path/to/log] ] \\	--touchlog \\       --restart_cmd \"apachectl restart\" \\        --compress [--noprune | --days N] --help

Where: --loglist specifies the path to a file containing the full pathnames of all the logs that are to be rotated. This option cannot be used with the --log option. --log specifies the full path to the log file to be rotated (multiple --log entries are allowed) --touchlog specifies that a new log should be created once the original log is rotated. (default is not to create the log) --restart_cmd specifies the command to restart the web server (default is apachectl restart) --compress specifies whether or not to compress the logs with gzip (default is off) --noprune disables automatic pruning of archived logs (default is off) --days specifies how many days to keep archived logs (default is 60, minimum value is 1) --help shows this message\n\n"; }