#!@PERL@ -- # -*- perl -*- # ==================================================================== # Copyright (c) 1995-1999 The Apache Group. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # # 3. All advertising materials mentioning features or use of this # software must display the following acknowledgment: # "This product includes software developed by the Apache Group # for use in the Apache HTTP server project (http://www.apache.org/)." # # 4. The names "Apache Server" and "Apache Group" must not be used to # endorse or promote products derived from this software without # prior written permission. For written permission, please contact # apache@apache.org. # # 5. Products derived from this software may not be called "Apache" # nor may "Apache" appear in their names without prior written # permission of the Apache Group. # # 6. Redistributions of any form whatsoever must retain the following # acknowledgment: # "This product includes software developed by the Apache Group # for use in the Apache HTTP server project (http://www.apache.org/)." # # THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY # EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # ==================================================================== # # This software consists of voluntary contributions made by many # individuals on behalf of the Apache Group and was originally based # on public domain software written at the National Center for # Supercomputing Applications, University of Illinois, Urbana-Champaign. # For more information on the Apache Group and the Apache HTTP server # project, please see . # # # cronosplit -- split log files into cronolog-compatible logs # # Copyright (c) 1996-1999 by Ford & Mason Ltd # # This software was submitted by Ford & Mason Ltd to the Apache # Software Foundation in December 1999. Future revisions and # derivatives of this source code must acknowledge Ford & Mason Ltd # as the original contributor of this module. All other licensing # and usage conditions are those of the Apache Software Foundation. # # cronosplit is loosly based on the splitlog script by # Roy Fielding # (splitlog is part of the wwwstat package, # see ) use Getopt::Long; $program = 'cronosplit'; $version = '@VERSION@'; # Parameters $MaxHandles = 50; $DirMode = 0775; # Patterns for log file entries (Common Log Format) and timestamps $log_entry_pattern = "^(\\S+) (\\S+) ([^[]+) \\[([^]]*)] \"([^\"]*)\" (\\S+) (\\S+)(.*)"; $timestamp_pattern = "^([ 0-3]?\\d)/([A-Za-z]+)/(\\d{4}):(\\d\\d):(\\d\\d):(\\d\\d) [+ -]\\d{1,4}"; # An associative array of month names and abbreviations %month = (Jan => 1, January => 1, Feb => 2, February => 2, Mar => 3, March => 3, Apr => 4, April => 4, May => 5, Jun => 6, June => 6, Jul => 7, July => 7, Aug => 8, August => 8, Sep => 9, September => 9, Sept => 9, Oct => 10, October => 10, Nov => 11, November => 11, Dec => 12, December => 12); @month = ("", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); @mmm = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); @days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); @ddd = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); # Process options (GetOptions("template=s", \$template, "print-invalid", \$PrintInvalids, "debug", \$debug, "verbose", \$verbose, "help", \$print_help, "version", \$print_version) and ($print_help or $print_version or $template)) or $print_help++; $verbose++ if $debug; # --debug implies --verbose # If version number requested, print it and exit if ($print_version) { print < $program is part of the cronolog package. The latest version of which can be found at: http://www.ford-mason.co.uk/resources/cronolog/ EOF exit(0); } # If help requested, print it and exit if ($print_help) { print <) { my($host, $ident, $authuser, $timestamp, $request, $status, $bytes, $trailer) = /$log_entry_pattern/; if (!($host && $ident && $authuser && $timestamp && $request && $status)) { if ($PrintInvalids) { print STDERR "$.:$saveline"; } next LINE; } if ($timestamp =~ /$timestamp_pattern/) { ($day, $mon, $year, $hour, $min, $sec) = ($1, $2, $3, $4, $5, $6); } else { if ($PrintInvalids) { print STDERR "$.:$saveline"; } next LINE; } next LINE unless defined($outfile = &get_handle($template, $day, $mon, $year, $hour, $min, $sec)); print($outfile $host, ' ', $ident, ' ', $authuser, ' [', $timestamp, '] "', $request, '" ', $status, ' ', $bytes, $trailer, "\n"); } close(INFILE); } # Get a file handle for a log file, closing the oldest handle if there # are too many handles open sub get_handle { my($template, $day, $mon, $year, $hour, $min, $sec) = @_; $mon = $month{$mon}; # Determine the filename from the template and time my($file) = $template; $file =~ s/%Y/sprintf("%04d", $year)/eg; $file =~ s/%m/sprintf("%02d", $mon)/eg; $file =~ s/%d/sprintf("%02d", $day)/eg; $file =~ s/%b/$mmm[$mon]/g; $file =~ s/%B/$month[$mon]/g; $file =~ s/%H/sprintf("%02d", $hour)/eg; $file =~ s/%M/sprintf("%02m", $min)/eg; $file =~ s/%S/sprintf("%02m", $sec)/eg; # See if we already have it open and ready to write return $handle if defined($handle = $OpenHandles{$file}); # See if we already have too many files opened if (($#HandlesInUse + 1) >= $MaxHandles) { local($oldkey) = shift @HandlesInUse; # close the oldest $handle = $OpenHandles{$oldkey}; delete $OpenHandles{$oldkey}; close $handle; } # Finally, try to open and remember a new handle for this pathkey $handle = ++$NextHandle; make_dirs($file); if (open($handle, ">>$file")) { push(@HandlesInUse, $file); $OpenHandles{$file} = $handle; return $handle; } else { warn "Failed open of $file: $!\n"; return undef; } } # Make any missing directories on the path specified # (this subroutine is not optimal). sub make_dirs { my($path) = shift; my($abs); # Strip off the filename bit $path =~ s!/[^/]*$!! or return; # Return early if the directory exists return if -d $path; # Trim off any leading '/' (remembering whether the path was # absolute or relative) $path =~ s!^(/)!!; $abs = $1; # Split what's left into directories my(@path) = split(/\//, $path); # Check each directory on the path foreach $i (0 .. $#path) { $path = $abs . join("/", (@path[0 .. $i])); print(STDERR "Testing $path\n") if $debug; print(STDERR "Making $path\n") if !-d $path and $debug; mkdir($path, $DirMode) unless -d $path; } }