2012-07-13 13 views
5

Próbuję skonfigurować skrypt, w którym generowany jest alert, gdy określony ciąg pojawia się w pliku dziennika.Jak potokować -f w awk

Rozwiązanie już na miejscu wyświetla cały plik dziennika raz na minutę i zlicza częstotliwość pojawiania się ciągu, używając znacznika czasu linii dziennika do zliczania tylko wystąpień z poprzedniej minuty.

Pomyślałem, że byłoby znacznie bardziej efektywne, aby zrobić to z ogonem, więc próbowałem następujące, jako test:

FILENAME="/var/log/file.log" 

tail -f $FILENAME | awk -F , -v var="$HOSTNAME" ' 
       BEGIN { 
         failed_count=0; 
       } 
       /account failure reason/ { 
         failed_count++; 
       } 
       END { 
         printf("%saccount failure reason (Errors per Interval)=%d\n", var, failed_count); 
       } 
' 

ale to po prostu zawiesza się i nie robi nic wyjściowego. Ktoś zasugerował tę niewielką zmianę:

FILENAME="/var/log/file.log" 

awk -F , -v var="$HOSTNAME" ' 
       BEGIN { 
         failed_count=0; 
       } 
       /account failure reason/ { 
         failed_count++; 
       } 
       END { 
         printf("%saccount failure reason (Errors per Interval)=%d\n", var, failed_count); 
       } 
' <(tail -f $FILENAME) 

ale to robi to samo.

Awk, którego używam (Uprościliśmy w powyższym kodzie) działa tak, jak jest używany w istniejącym skrypcie, w którym są przesyłane wyniki z grep "^ $ TIMESTAMP".

Moje pytanie brzmi: w jaki sposób można uzyskać ogon -f do pracy z awk?

+4

Kiedy 'tail -f', twój skrypt awk nigdy nie dojdzie do KONIEC. Wciąż liczycie błędy, ale nigdy niczego nie drukujecie. Potrzebujesz innego warunku (na przykład, wykrywając, że to nowy dzień), który uruchamia printf i resetuje licznik.Pokaż nam próbkę Twojego dziennika, a my możemy zaproponować poprawkę. – ghoti

Odpowiedz

4

Zakładając swój dziennik wygląda mniej więcej tak:

Jul 13 06:43:18 foo account failure reason: unknown 
│ │  
│ └── $2 in awk 
└────── $1 in awk 

można zrobić coś takiego:

FILENAME="/var/log/file.log" 

tail -F $FILENAME | awk -v hostname="$HOSTNAME" ' 
    NR == 1 { 
     last=$1 " " $2; 
    } 
    $1 " " $2 != last { 
     printf("%s account failure reason (Errors on %s)=%d\n", hostname, last, failed); 
     last=$1 " " $2; 
     failed=0; 
    } 
    /account failure reason/ { 
     failed++; 
    } 
' 

pamiętać, że zmieniłem to tail -F kapitału (F), ponieważ obsługuje protokół starzenie się. Nie jest to obsługiwane w każdym systemie operacyjnym, ale powinno działać we współczesnych BSD i Linuces.

Jak to działa?

Skrypty awk składają się z zestawów test { commands; } ocenianych względem każdego wiersza wejścia. (Istnieją dwa specjalne testy, BEGIN i END których polecenia uruchomienia, gdy awk zaczyna i kiedy awk końce, odpowiednio. W swoim pytaniu, awk nigdy nie skończyła, więc kod END został nigdy nie zabraknie.)

Skrypt powyżej ma trzy sekcje testowania/polecenia:

  • W pierwszym, NR == 1 jest testem, który sprawdza wartość true tylko w pierwszym wierszu wejścia. Polecenie, które uruchamia, tworzy wartość początkową dla zmiennej last, używanej w następnej sekcji.
  • W drugiej sekcji sprawdzamy, czy "ostatnia" zmienna uległa zmianie od czasu ostatniego zapisanego wiersza. Jeśli jest to prawda, oznacza to, że oceniamy dane nowego dnia. Nadszedł czas, aby wydrukować podsumowanie (log) z ostatniego miesiąca, zresetować nasze zmienne i przejść dalej.
  • Po trzecie, jeśli linia, którą oceniamy, pasuje do wyrażenia regularnego /account failure reason/, zwiększamy licznik.

Wyczyść jak błoto? :-)

+0

+1 - Aby zrobić błędy/dzień, musisz liczyć dni i wykonać podział. Możesz też zmienić swoje sformułowanie na "Błędy wczoraj" i zresetować "failed_count". –

+0

Ooh, na miejscu! Nie mam pojęcia, co on robi, ale fajny, dzięki! – mazz0

+0

@DennisWilliamson - racja, dzięki za wskazanie tego. Zaktualizowałem odpowiedź, aby kod zapewniał wyraźniejsze wyniki. – ghoti