http://paperlined.org/dev/web/watch_cgi_errors.pl

#!/usr/bin/perl

# Watch the apache error log, and present the output in a way that's useful for debugging script errors
#
# This makes it viable (nay, desirable) to debug things via warn+Dumper in Perl.
#
# NOTE: This DOES leave out some error messages that you might consider important.  This script only focuses on
#       error messages that are likely generated from .cgi scripts.
#       If you'd like to tweak should_error_be_ignored(), feel free.

    use strict;
    use warnings;
    use Data::Dumper;

open PIN, "</var/log/apache2/error.log"    or die $!;
seek(PIN, -100000, 2);        # move to 100000 bytes from the end
my $throwaway = <PIN>;      # ignore half-line
my $last_nonmsg = '';
while (1) {
    while (<PIN>) {
        my %parsed;     # one error_log record that has been parsed
        @parsed{'non_message', 'time', 'type', 'client', 'message'} = ($_ =~ m#^(\[([^\]]*)\]\s*\[([^\]]*)\]\s*\[([^\]]*)\])\s?([^\n\r]*)#s);
        $parsed{message} =~ s/, referer: (\S+)$//s  and $parsed{referer} = $1;
        #print Dumper \%parsed; exit;
        next if (should_error_be_ignored(\%parsed));
        if ($parsed{non_message} ne $last_nonmsg) {
            # print the header
            print "\n";
            print "-"x20, $parsed{non_message}, "-"x20, "\n";
        }
        print $parsed{message}, "\n";
        $last_nonmsg = $parsed{non_message};
    }
    select(undef,undef,undef,0.25);
    seek(PIN, tell(PIN), 0);        # reset the EOF flag
}


sub should_error_be_ignored {
    my ($parsed) = @_;
    local $_ = $parsed->{message};

    if (s/^File does not exist: //) {
        return 1 if (m#/favicon\.ico$#);
        return 1 if (/\.(?:gif|png|jpe?g)$/i);
        return 0;
    }

    return 1 if (m#^attempt to invoke directory as script: #);

    return 0;
}

Generated by GNU enscript 1.6.4.