Posts Tagged ‘perl’

Ujarzmione logi apache

Wednesday, August 12th, 2009

Na co dzień pracuję z aplikacją, która wyrzuca bardzo dużo “śmieci” do logów. Tym samym zapycha ona error log, który z nazwy powinien zawierać błędy, a nie informacje o niezainicjalizowanej zmiennej X. Postanowiłem ukrócić ten proceder i filtrować wychodzące z procesów apache`a komunikaty.

Wykorzystałem do tego perla, gdyż dość sprawnie radzi on sobie z obróbką tekstu i wyrażeniami regularnymi. Poniżej zawartość skryptu apache-logfilter.pl

#!/usr/bin/perl -w

use strict;

$|=1;   # use unbuffered output

my $logfile;

# check if logfile was passed as 1st argument
if ($ARGV[0])   {
$logfile=$ARGV[0];
}

# assign /dev/null as logfile unless it is already defined
$logfile="/dev/null" unless ($logfile);

# set umask
umask 0022;
my $loghandler=open(LOGFILE,'>>',$logfile);

# autoflush file handler
select((select(LOGFILE), $| = 1)[0]);

# inifinite loop over input from STDIN
while (<STDIN>) {

# omit unwanted lines matching the following patterns
next if (/^Use of uninitialized value/);
next if (/^"my" variable/);
next if (/^Subroutine \w+ redefined/);
next if (/^Variable ".*?" will not stay shared/);
next if (/^Odd number of elements in hash/);
next if (/^Argument ".*?" isn't numeric/);
next if (/^Useless use of .*? in void context/);
next if (/^substr outside of string at/);
next if (/^Unquoted string ".*?" may clash/);
next if (/^Scalar value @.*? better written as/);
next if (/^Parentheses missing around/);

# print to our logfile
print LOGFILE "$_";
}

Posiadając już taki skrypt należy przekazać w konfiguracji apache`a jego wywołanie. Odbywa się to za pomocą pipe`a przez który przekazywane są komunikaty do skrypty. W tym przypadku jako parametr podana jest ścieżka do właściwego pliku logu, do którego dopisywane są wiadomości (nie należy zapomnieć o właściwiej konfiguracji logrotate!).
Przykładowa część konfiguracji:


ErrorLog "|/usr/local/bin/apache-logfilter.pl /var/log/apache/error_log"

Ciekawą rzeczą jaką napotkałem tutaj był problem buforowanego wyjścia. Otóż do logu nie docierały żadne nowe wiadomości. Wielokrotnie sprawdzałem poprawność skryptu i za każdym razem działał on poprawnie zapuszczony z palca. Po krótkich poszukiwaniach znalazłem zmienną $|, której to niezerowe ustawienie powinno mój problem rozwiązać. A jednak nie rozwiązało. Dopiero wymuszenie tego na uchwycie otwartego pliku dało pożądane rezultaty. Odpowiada za to następujące wywołanie:


select((select(LOGFILE), $| = 1)[0]);

Teraz wszystko śmiga jak należy – czytelność logów zwiększyła się znacząco, a ich rozmiar zmniejszył się kilkukrotnie.