#!/usr/bin/perl use strict; use warnings "all"; use IO::File; use IO::Zlib; use Date::Manip; use DateTime; use DateTime::Format::Apache; =head1 NAME rotate_old_logs - rotates old Apache logfiles =head1 SYNOPSIS $ ./rotate_old_logs =head1 DESCRIPTION Splits apart a preexisting Apache common format logfile into months. For use if you have not been rotating logs and want old logs as well as new ones to be split monthly. The UTC time zone is used to determine the beginning of each month. To switch over, you could: 1. change the webserver's logging configuration to this: CustomLog "|bin/rotatelogs /dir/logfile-%Y-%m" 2. shut down the webserver 3. run this script 4. uncompress the latest month's log (so rotatelogs appends to it) 5. restart the webserver Shutting down the webserver is not ideal, I know, but this ensures you properly deal with the current month. =head1 AUTHOR Scott Lamb =cut foreach my $name (@ARGV) { my $infile = new IO::File($name, "r") or die; my $cur_mon_str; my $outfile; print "Starting $name\n"; while (<$infile>) { my ($date_str) = m{ ^\d+\.\d+\.\d+\.\d+ \s # IP address [^ ]+ \s # not sure [^ ]+ \s # not sure \[([^\]]+)\] \s # date }x or die "Unrecognized line"; my $date = DateTime::Format::Apache->parse_datetime($date_str); $date->set_time_zone('UTC'); my $mon_str = sprintf("%04d-%02d", $date->year(), $date->month()); if (!defined($cur_mon_str) || $cur_mon_str ne $mon_str) { print "\tStarting $mon_str\n"; $outfile = new IO::Zlib($name . "-$mon_str.gz", "a") or die; $cur_mon_str = $mon_str; } print $outfile $_; } }