#!/usr/bin/perl -w
#
# error_log_ai - Apache error log analysis script
# Apache Security, http://www.apachesecurity.net
# Copyright (C) 2004 Ivan Ristic <ivanr@webkreator.com>
#
# This script implements the Artificial Ignorance concept (see
# http://www.ranum.com/security/computer_security/papers/ai/),
# for the Apache error log.
# 
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

# This script expects data from the Apache error on standard input.
#
# Example:
#
#   cat error_log | ./error_log_ai.pl
#
# It will output the short version, hopefully containing only the
# relevant information.
#

# TODO logwatch integration
#
# TODO remove regular expressions for noise supperssion
#      out of the code and to the top of the file

# loop through the lines that are fed to us
while (defined($line = <STDIN>)) {

    # ignore "noisy" lines
    if (!( ($line =~ /Processing config/)
        || ($line =~ /Server built/)
        || ($line =~ /suEXEC/) )) {

        # remove unique features of log entries
        $line =~ s/^\[[^]]*\] //;
        $line =~ s/\[client [^]]*\] //;
        $line =~ s/\[unique_id [^]]*\]//;
        $line =~ s/child pid [0-9]*/child pid X/;
        $line =~ s/child process [0-9]*/child process X/;

        # add to the list for later
        push(@lines, $line);
    }
}

@lines = sort @lines;

# replace multiple occurences of the same line
$count = 0;
$prevline = "";
foreach $line (@lines) {
    next if ($line =~ /^$/);

    if (!($line eq $prevline)) {
        if ($count != 0) {
            $prefix = sprintf("%5i", $count);
            push @outlines, "$prefix $prevline";
        }
        $count = 1;
        $prevline = $line;
    } else {
        $count++;
    }
}
undef @lines;

@outlines = sort @outlines;
print "--httpd begin------\n";
print reverse @outlines;
print "--httpd end--------\n";
