NFsec Logo

Odkrywając access_log Apache

23/08/2009 w Hacks & Scripts Brak komentarzy.  (artykuł nr 135, ilość słów: 1045)

P

rzedstawiony skrypt jest tłumaczeniem “Exploring the Apache access_log” z książki “Wicked Cool Shell Scripts” autorstwa Dave’a Taylor’a udostępnionym on-line (Skrypt #84) na stronie www.intuitive.com. Do tłumaczenia zostało dodane także parę informacji od tłumacza.

   Jeśli używasz serwera Apache lub podobnego serwera WWW, który także wykorzystuje Common Log Format – istnieje trochę możliwości wykonania analiz statystycznych, przy pomocy skryptu powłoki. Standardowa konfiguracja dla serwera posiada zapisywane pliki access_log oraz error_log dla strony internetowej; nawet ISP (dostawcy Internetu) udostępniają surowe dane swoim klientom, lecz jeśli posiadasz własny serwer, powinieneś definitywnie posiadać i archiwizować te cenne informacje.

Typowy wiersz w pliku access_log wygląda tak:

63.203.109.38 - - [02/Sep/2003:09:51:09 -0700] "GET /custer HTTP/1.1"
301 248 "http://search.msn.com/results.asp?RS=CHECKED&FORM=MSNH&
v=1&q=%22little+big+Horn%22" "Mozilla/4.0 (compatible; MSIE 6.0;
Windows NT 5.0)"

Tabela 1 pokazuje wartości dla formatu common log.

Tabela 1. Układ formatu Common Log
Kolumna Wartość
1 IP hosta korzystającego z serwera
2 – 3 Informacje o zabezpieczonych połączeniach https/SSL
4 Przesunięcie daty i strefy czasowej dla konkretnego żądania
5 Wywołana metoda
6 Zażądany URL
7 Użyty protokół
8 Kod wynikowy
9 Liczba przetransferowanych bajtów
10 Adres strony odsyłającej
11 Łańcuch znaków do identyfikacji przeglądarki

 

Wynik kodu (pole 8) 301 wskazuje powodzenie. Adres strony odsyłającej (pole 10) wskazuje adres URL strony odwiedzonej przez internautę zaraz przez zażądaniem strony z tego serwisu: Widać, że użytkownik był na wyszukiwarce search.msn.com (MSN) i szukał wyrażenia “little big Horn”. W wynikach tego wyszukiwania znajdował się link do adresu URL /custer na tym serwerze.

Liczbę odwiedzin strony można szybko ustalić poprzez policzenie ilości słów w pliku dziennika oraz zakres dat poprzez porównanie dziesięciu pierwszych i ostatnich wierszy:

$ wc -l access_log
10991 access_log
$ head -1 access_log ; tail -1 access_log
64.12.96.106 - - [13/Sep/2003:18:02:54 -0600] ...
216.93.167.154 - - [15/Sep/2003:16:30:29 -0600] ...

Z tymi wytycznymi w umyśle, oto skrypt, który generuje wiele użytecznych statystyk, zakładając, że plik access_log jest w formacie Apache.

Skrypt:

#!/bin/sh

# webaccess - analizuje plik Apache-format access_log , wyciągając
# przydatne dane statystyczne

bytes_in_gb=1048576
scriptbc="$HOME/bin/scriptbc"
nicenumber="$HOME/bin/nicenumber"
host="intuitive.com"

if [ $# -eq 0 -o ! -f "$1" ] ; then
  echo "Usage: $(basename $0) logfile" >&2
  exit 1
fi

firstdate="$(head -1 "$1" | awk '{print $4}' | sed 's/\[//')"
lastdate="$(tail -1 "$1" | awk '{print $4}' | sed 's/\[//')"

echo "Results of analyzing log file $1"
echo ""
echo "  Start date: $(echo $firstdate|sed 's/:/ at /')"
echo "    End date: $(echo $lastdate|sed 's/:/ at /')"

hits="$(wc -l < "$1" | sed 's/[^[:digit:]]//g')"

echo "        Hits: $($nicenumber $hits) (total accesses)"

pages="$(grep -ivE '(.txt|.gif|.jpg|.png)' "$1" |wc -l|sed 's/[^[:digit:]]//g')"

echo "   Pageviews: $($nicenumber $pages) (hits minus graphics)"

totalbytes="$(awk '{sum+=$10} END {print sum}' "$1")"

echo -n " Transferred: $($nicenumber $totalbytes) bytes "

if [ $totalbytes -gt $bytes_in_gb ] ; then
  echo "($($scriptbc $totalbytes / $bytes_in_gb) GB)"
elif [ $totalbytes -gt 1024 ] ; then
  echo "($($scriptbc $totalbytes / 1024) MB)"
else
  echo ""
fi

# now let's scrape the log file for some useful data:

echo ""
echo "The ten most popular pages were:"

awk '{print $7}' "$1" | grep -ivE '(.gif|.jpg|.png)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -10

echo ""

echo "The ten most common referrer URLs were:"

awk '{print $11}' "$1" | \
grep -vE "(^"-"$|/www.$host|/$host)" | \
sort | uniq -c | sort -rn | head -10

echo ""
exit 0

Jak to działa:

Skrypt ten tylko pozornie wygląda na skomplikowany. Łatwiej jest go ujrzeć patrząc na każdy blok jako odrębny, mały skrypt. Dla przykładu, pierwszych kilka wierszy wyodrębnia pierwszą i ostatnią datę poprzez proste wyciągnięcie czwartego pola z pierwszego i ostatniego wiersza pliku. Liczba trafień obliczana jest przez policzenie liczby wierszy (przy pomocy polecenia wc), a liczbę wyświetleń strony stanowi po prostu liczba trafień minus różnego rodzaju żądania obrazków czy surowych plików tekstowych (to jest plików z rozszerzeniami .gif, .jpg, .png lub .txt). Całkowita liczba przetransferowanych bajtów jest liczona poprzez podsumowanie wartości dziesiątego pola ze wszystkich wierszy, a następnie wywoływana jest funkcja nicenumber, aby przedstawić wynik w czytelny sposób. Najbardziej popularne strony, można wyłapać poprzez wyodrębnienie zażądanych stron z pliku dziennika; zasłaniając wpisy dotyczące plików graficznych; sortując za pomocą polecenia: uniq -c, aby obliczyć liczbę wystąpień każdego unikatowego wiersza; oraz ostatecznie, ponownie sortując w celu upewnienia się, że najczęściej pojawiające się wiersze były na samej górze. Kod wygląda tak:

awk '{print $7}' "$1" | grep -ivE '(.gif|.jpg|.png)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -10

Warto zauważyć, że stosujemy w małym stopniu normalizację. Wywołanie sed wyodrębnia wszystkie slashe (/), tak aby /podkatalog/ i /podkatalog zostały policzone jako to samo żądanie.

Podobnie do sekcji wyławiającej najbardziej popularne strony, następna sekcja wyciąga informacje o stronach odsyłających:

awk '{print $11}' "$1" | \
grep -vE "(^\"-\"$|/www.$host|/$host)" | \
sort | uniq -c | sort -rn | head -10

Fragment ten wyodrębnia pole 11 z pliku dziennika, zasłaniając obydwa wpisy dotyczące bieżącego hosta, jak i wpisy w postaci “-” (wartość ta jest przesyłana, gdy przeglądarka blokuje dane o stronie odsyłającej), a następnie wprowadzając rezultat do tej samej sekwencji sort|uniq -c|sort -rn|head -10, aby uzyskać dziesięć najpopularniejszych stron odsyłających.

Uruchamianie skryptu:

W celu wykonania tego skryptu jako argument wywołania należy podać nazwę pliku dziennika Apache (lub innego w formacie Common Log Format).

Rezultaty:

Rezultaty uruchomienia tego skryptu na typowym pliku dziennika dają wiele informacji:

$ webaccess /web/logs/intuitive/access_log
Results of analyzing log file /web/logs/intuitive/access_log
Start date: 13/Sep/2003 at 18:02:54
End date: 15/Sep/2003 at 16:39:21
Hits: 11,015 (total accesses)
Pageviews: 4,217 (hits minus graphics)
Transferred: 64,091,780 bytes (61.12 GB)
The ten most popular pages were:
862 /blog/index.rdf
327 /robots.txt
266 /blog/index.xml
183
115 /custer
96 /blog/styles-site.css
93 /blog
68 /cgi-local/etymologic.cgi
66 /origins
60 /coolweb
The ten most common referrer URLs were:
96 "http://booktalk.intuitive.com/"
18 "http://booktalk.intuitive.com/archives/cat_html.shtml"
13 "http://search.msn.com/results.asp?FORM=MSNH&v=1&q=little+big+horn"
12 "http://www.geocities.com/capecanaveral/7420/voc1.html"
10 "http://search.msn.com/spresults.aspx?q=plains&FORM=IE4"
9 "http://www.etymologic.com/index.cgi"
8 "http://www.allwords.com/12wlinks.php"
7 "http://www.sun.com/bigadmin/docs/"
7 "http://www.google.com/search?hl=en&ie=UTF-8&oe=UTF-8&q=cool+web+pages"
6 "http://www.google.com/search?oe=UTF-8&q=html+4+entities"

Modyfikowanie skryptu:

Problem jaki występuje podczas analizowania plików dziennika serwera WWW jakim jest Apache jest taki, że czasami dwa różne adresy URL tak naprawdę mogą oznaczać tę samą stronę. Dla przykładu: /custer/ oraz /custer/index.shtml są tymi samymi stronami, więc podczas obliczania dziesięciu najpopularniejszych stron należy wziąć to pod uwagę. Konwersja przy pomocy wywołania sed powoduje, że /custer i /custer/ nie są uważane za różne wywołania, lecz poznanie domyślnej nazwy pliku dla każdego katalogu może być trochę trudniejsze. Pożytek jaki płynie z analizy dziesięciu najpopularniejszych stron odsyłających może być jeszcze większy, kiedy obetniemy ich adresy URL do podstawowej nazwy domenowej (np. slashdot.org).

Więcej informacji: Shell Script, awk –usage, man head, sort, uniq

Kategorie K a t e g o r i e : Hacks & Scripts

Tagi T a g i : , , , , , , ,

Komentowanie tego wpisu jest zablokowane.