Statistiche Generali dai log di Apache con AWK

postato in: Articoli, Guida | 0

awk_big_parte3

Buongiorno. Oggi post molto particolare. Vediamo infatti un'applicazione pratica del linguaggio Awk applicato all'analisi dei file di log del server Apache.

Su Tux Maniacs abbiamo affrontato in vari articoli Apache, a vari gradi di difficoltà e di approfondimento. Ci siamo tuttavia soffermati poco su uno dei “prodotti” di questo server: i file di log.

Come sappiamo esistono due tipi di file:

  • Access.log: registrano tutte le richieste di pagina che arrivano ad Apache.
  • Error.log: registrano tutti gli errori che il server incontra durante la sua esecuzione.

In questo esempio ci concentreremo sugli access log. Per poterci lavorare sopra abbiamo bisogno di alcuni file di prove e per questo utilizzeremo un file di access pubblico della NASA, liberamente scaricabile. Scarichiamo quindi il suddetto file da questo indirizzo dal browser o con il seguente comando:

wget -c ftp://ita.ee.lbl.gov/traces/NASA_access_log_Aug95.gz

Una volta scaricato, decomprimiamo l'archivio con:

gzip -dk NASA_access_log_Aug95.gz

e ne esploriamo una parte dando:

head access_log_Aug95

Come possiamo vedere il file di log è suddiviso a righe, ognuna delle quali è detto record, e registra una richiesta da parte di un client al nostro server.

La formattazione è fissa e regolare, per cui è possibile analizzarlo facilmente tramite Awk o altri programmi simili.

 

 

PERCHÈ PROPRIO LE STATISTICHE GENERALI
Il requisito principe per gestire correttamente un server è ben riassunto dal motto:

Always know what happens

Che potremmo tradurre “de noi atri” in: conosci sempre ciò che succede sul tuo server. Quindi iniziamo immediatamente a scrivere un piccolo programma in Awk (di cui abbiamo discusso ampiamente qua e qua) per riassumere alcune statistiche base, difficilmente reperibili a occhio nudo.

Innanzi tutto vogliamo che il programma prenda in input un file e in output restituisca:

  • Il periodo di tempo registrato dal log.
  • Il numero totale di visualizzazioni.
  • Il numero totale di errori.

Il file di access possiamo pensarlo come suddiviso in colonne e separato dal separatore di default – lo spazio.
Come abbiamo visto in questo post, possiamo selezionare le colonne tramite l'operatore $. Se stampiamo a video le varie colonne possiamo osservare che:

  • $1 : indirizzo ip.
  • $2 : -
  • $3 : -
  • $4 : data della richiesta.
  • $5 : time zone.
  • $6 : metodo della richiesta, che può essere GET o POST.
  • $7 : URL relativo della pagina richiesta.
  • $8 : versione del protocollo HTTP.
  • $9 : Codice di status della risposta.
  • $10 : byte della risposta.

Iniziamo dal primo punto che è il più facile. I file di log sono ordinati in ordine cronologico. Quindi ci basta stampare la prima data, seguita dall'ultima.
Per stampare a video la data iniziale possiamo utilizzare la supervariabile NR che conta il numero di righe processate. Quindi non ci basta che stampare nel momento in cui NR raggiunge il valore 1.
Viceversa per quanto riguarda la data finale, la faccenda è molto più semplice. Sappiamo da questo post che il blocco END è attivato solamente alla fine dell'esecuzione, ossia quando è raggiunta l'ultima riga.

Creiamo un file per il programma Awk con:

touch apache.awk

e inseriamo al suo interno il seguente codice:

#! /bin/awk -f

BEGIN {
    start_date = "";
}

NR==1 {
    start_date = $4 $5;
}

END {
    print "Periodo: " start_date " -> "$4 $5;
}

E lo eseguiamo con:

awk -f apache.awk access_log_Aug95

 

data

 

Ora passiamo al contare il numero di richieste ricevute. Come sappiamo il protocollo HTTP ha dei codici di risposta che permettono di sapere se la richiesta ha avuto successo oppure no. A noi interessa contare tutte le richieste che hanno codice di successo ossia: 200 OK.

Selezioniamo quindi la colonna 9 e se uguale a 200, incrementiamo un contatore. Utilizzeremo l'operatore ~ introdotto qua.
Il nodo chiave da aggiungere sarà:

$9 ~ /200/ {
    success_count = success_count + 1;
}

 

200

 

Allo stesso modo raccogliamo le informazioni sugli errori. Ora dato che gli errori sono molti e molto diversificati tra di loro possiamo leggere una lista veramente esaustiva a questo link. Noi ci concentreremo sui seguenti:

  • Client error 4xx:
    • 400 Bad Request : il client ha fatto una richiesta mal formata, e il server non è in grado di rispondere.
    • 401 Unauthorized : il client ha cercato di effettuare l'accesso a una pagina accessibile solo previo login.
    • 403 Forbidden : il server ha ricevuto una richiesta a cui però non gli è permesso rispondere positivamente.
    • 404 File not found : l'errore più famoso del www. La pagina richiesta non esiste.
  • Server error 5xx:
    • 500 Internal Server Error : il server ha riscontrato un errore interno inatteso.
    • 501 Not Implemented : il server ha ricevuto una richiesta di una funzionalità a cui non sa espletare.
    • 502 Bad Gateway : se il server agisce come proxy o gateway, ha ricevuto una risposta inattesa dal proxy/gateway di livello superiore, e quindi non può espletare la richiesta.
    • 503 Service Unavailable : il server non è in grado nemmeno di ricevere le richieste.

Analogamente alla gestione del codice 200, per tutti questi casi ci servirà una variabile contatore per ogni codice e un blocco in grado di attivarsi e incrementare uno specifico contatore.
I nodi saranno quindi nel formato:

$9 ~ /n00/ {
    count = count + 1;
}

Il file apache.awk sarà quindi:

#! /bin/awk -f

BEGIN {
    start_date = "";
    success_count = 0;
    count_400 = 0;
    count_401 = 0;
    count_403 = 0;
    count_404 = 0;
    count_500 = 0;
    count_501 = 0;
    count_502 = 0;
    count_503 = 0;
}

$9 ~ /200/ {
    success_count = success_count + 1;
}

$9 ~ /400/ {
    count_400 = count_400 + 1;
}

$9 ~ /401/ {
    count_401 = count_401 + 1;
}

$9 ~ /403/ {
    count_403 = count_403 + 1;
}

$9 ~ /404/ {
    count_404 = count_404 + 1;
}

$9 ~ /500/ {
    count_500 = count_500 + 1;
}

$9 ~ /501/ {
    count_501 = count_501 + 1;
}

$9 ~ /502/ {
    count_502 = count_502 + 1;
}

$9 ~ /503/ {
    count_503 = count_503 + 1;
}

NR==1 {
    start_date = $4 $5;
}

END {
    print "Periodo: " start_date " -> "$4 $5;
    print "Numero totale di richieste: " success_count
    print "Client error:"
    print " 400 = "count_400
    print " 401 = "count_401
    print " 403 = "count_403
    print " 404 = "count_404
    print "Server error:"
    print " 500 = "count_500
    print " 501 = "count_501
    print " 502 = "count_502
    print " 503 = "count_503
}

e eseguendolo con il comando:

awk -f apache.awk access_log_Aug95

otteniamo:

errorcode

 

 

CONCLUSIONI
Con questo post volevamo far capire, tramite un semplice esempio, quanto potente può essere il linguaggio Awk, e che, se utilizzato al meglio, riesce a risolvere veramente molti problemi.

Al prossimo post! 😉

 

 

FONTI

Dottore in Informatica. Appassionato di computer fin dal primo PC Olivetti con Windows 95 e la bellezza di 8 MB di RAM.
Utilizzatore Linux da 5 anni, credo profondamente nella filosofia open source.
Dopo tante distro provate sul mio fidato Toshiba, uso Fedora per lo studio e il divertimento.

Lascia un commento