I provider dei servizi di hosting utilizzano sistemi diversi per accedere al pannello di controllo di un server remoto. Possiamo avere interfacce grafiche avanzate, soluzioni custom o accesso solamente via terminale, tipicamente su connessione ssh. Qualunque sia l'interfaccia a nostra disposizione, molto spesso avremo a che fare con un web server, come ad esempio Apache, che ospita i nostri siti o applicazioni. Anche se utilizziamo un'interfaccia grafica, probabilmente avremo un'icona o pulsante dove controllare il file di log del web server. Il file di log dovrebbe essere uno dei primi posti dove guardare quando ci troviamo davanti ad un problema inaspettato, un malfunzionamento o un disservizio.

Se accediamo al server remoto via terminale, potrebbe essere comodo analizzare il contenuto del file di log direttamente dalla shell, mentre siamo connessi alla macchina remota. Se invece visualizziamo il file in un pannello del browser, o possiamo scaricarlo in locale, ci troveremo tra le mani un file di testo di notevoli dimensioni. In entrambi gli scenari, uno dei metodi migliori di analizzare il contenuto di un file è l'utilizzo dei comandi di shell Linux.

Precisiamo il senso di questa affermazione: anche se abbiamo scaricato il file in locale in formato testo, spesso è più efficiente spostare il file su una macchina Linux (o semplicemente dual boot) e procedere con l'analisi via terminale. Persino restando fedeli a Windows possiamo seguire un procedimento simile, scaricando gli strumenti che permettono di emulare le principali funzionali (come ad esempio il grep per Windows).

Questo è forse uno dei pochi casi in cui la modalità di lavoro via terminale supera in efficienza e velocità di un'interfaccia grafica a finestre. Possiamo affidarci ad un editor potente come Notepad++, ma difficilmente andremo oltre il classico Find (Ctrl + F). Come vedremo i comandi Linux di shell permettono analisi molto più raffinate e veloci.

Comandi elementari

Le istruzioni più semplici per analizzare il contenuto di un file sono head e tail. Com'è facile intuire dal loro nome, il comando head mostra le prime righe di un file, mentre tail visualizza la fine (letteralmente “la coda”) del file. La sintassi è semplice e intuitiva

head prova.log

tail prova.log

dove prova.log è il nome dell'ipotetico file che vogliamo analizzare. Fin qui non abbiamo nulla di nuovo, perché qualsiasi editor permette di ottenere lo stesso risultato semplicemente andando in cima o in fondo al file (Ctrl + Home e Ctrl + Fine). Il vantaggio, in questo caso, si manifesta solo se ci troviamo sulla stessa macchina del server e vogliamo controllare il file di log in tempo reale, per vedere cosa succede “sotto al cofano”. Ecco che alcune opzioni del comando tail diventa utilissime, ad esempio

tail -f prova.log

segue (follow) la coda del file mentre cresce, ovvero ci mostrerà sempre le ultime righe, man mano che il file viene aggiornato o modificato. In questo modo la finestra del terminale diventa un monitor del web server, nel senso di monitoraggio in tempo reale dell'applicazione.

I comandi tail ed head offrono altre opzioni interessanti, ma non rappresentano il punto di forza dell'analisi via terminale. Il vero protagonista è il comando grep, che merita una trattazione a parte.

Il comando grep

L'istruzione grep è forse la più utile tra quelle offerte dal terminale Linux, specialmente quando dobbiamo analizzare files di grosse dimensioni. Il comando cerca le occorrenze di una stringa (specificata dall'utente) all'interno del file, ma non solo: possiamo cercare espressioni regolari, all'interno di cartelle (in modo ricorsivo), o addirittura in tutto il file system. L'istruzione grep potenzia e generalizza la funzione “Trova risorse” o “Cerca nei Files” comune a molti sistemi operativi o editor di testo. Il vantaggio, in termini di velocità e efficacia, diventa evidente con qualche esempio pratico. Per fissare le idee supponiamo di avere un file di log di nome prova.log, al cui interno si trovano alcuni errori. Il nostro obbiettivo è trovare gli errori, capire quanti sono, e capire se hanno una causa comune. Posizioniamoci nella stessa cartella del file e digitiamo il comando

grep errore prova.log

se il log è in inglese, probabilmente non troveremo alcun risultato, perché abbiamo cercato una parola italiana (“errore”). A questo punto potrebbe venirci il dubbio che la parola da individuare nel log sia in inglese (cioè “error”), o che vada specificata in maiuscolo (cioè “ERROR”). Nessun problema: il comando grep ci viene incontro permettendoci di trovare ciò che cerchiamo senza porci questi problemi, usando la sintassi

grep -i err prova.log

che ritorna esattamente tutte le righe dove compare un errore nel log. Il “trucco” si basa sull'introduzione dell'opzione -i, che significa “esegui una ricerca case insensitive”, e sulla scelta di cercare solo una parte della parola (“err” anziché “errore”): in tal modo verranno restituite tutte le righe che contengono la stringa “err”, come ad esempio “errore”, “errata”, “error”, “errabondo” ecc.

Questo è solo l'inizio. Visualizzare le righe con l'errore non ci basta: vogliamo anche capire se gli errori hanno una causa comune. Per farlo proviamo ad assumere che la causa sia "loggata" qualche riga sopra il messaggio d'errore: per analizzare gli indiziati proviamo il comando

grep -i -B5 err prova.log

dove l'opzione -B5 significa “stampa a video anche le 5 righe before (prima) ogni risultato”. Ovviamente abbiamo a disposizione anche l'opzione complementare, ovvero -A, che permette di visualizzare n righe dopo (after) le occorrenze trovate dal grep.

Dopo aver imparato ad analizzare il contenuto di un singolo file, possiamo passare all'analisi massiva di molti files diversi, scenario piuttosto frequente in un ambiente di produzione, dove i files di log sono più di uno e non sappiamo dove cercare l'errore. Alcuni comandi utili potrebbero essere

grep -ir error *

per cercare ricorsivamente in tutte le directories. Se il comando ritorna troppi risultati possiamo filtrarli usando il pipe e un grep negativo, ad esempio

grep -ir error * | grep -vi solved

il comando qui sopra significa: “cerca la stringa err, sia essa maiuscola o minuscola, in tutti i files e cartelle sotto il percorso corrente, eliminando dai risultati le righe che contengono la parola solved (minuscola o maiuscola)”. Se poi vogliamo anche sapere quanti sono gli errori, basterà aggiungere in coda l'istruzione wc (word count) con l'opzione -l (conta le righe)

grep -ir error * | grep -vi solved | wc -l