Centralizzare i log mediante Elasticsearch, Logstash e Kibana

Elasticsearch   Logstash   Kibana

Uno dei principali problemi che si rilevano in fase di debug delle anomalie relative ad applicazioni è la frammentazione delle informazioni. Tanti log, buona parte dei quali inutili, sono sparsi ovunque nelle macchine interessate all’erogazione di questo o quel servizio.
Tipicamente quando si tratta di servizi ripartiti su più macchine è sempre necessario aprire diverse console all’interno delle quali, per ciascuna macchina, il (o i) file di log vengono aperti, filtrati stampati e via così, sino ad ottenere una situazione degna di Sherlock Holmes, in cui solo consumati ed abili detective riescono a trovare l’indizio che sfugge ai più.

Esiste però una via migliore per gestire enormi quantità di log in una forma centralizzata, facilmente ricercabile e che usi un’interfaccia gradevole. Si tratta della combinazione di tre software: Elasticsearch, Logstash e Kibana.

Prerequisiti: Java e spazio

Elasticsearch e Logstash sono software scritti in java e per funzionare necessitano appunto dell’ambiente operativo omonimo, disponibile per tutte le maggiori distribuzioni Linux.
Per verificare se java è installato nel sistema utilizzato è sufficiente lanciare il comando:

root@logstash:~# java -version
java version "1.6.0_35"
Java(TM) SE Runtime Environment (build 1.6.0_35-b10)
Java HotSpot(TM) 64-Bit Server VM (build 20.10-b01, mixed mode)

La versione del sistema in questione è 1.6.0_35. Se non si dovesse disporre di java sarà possibile recuperarlo dal sito ufficiale, presso il seguente link.

Da considerare in fase preliminare è anche la questione spazio. Nel progetto descritto verrà creata la cartella /logs:

root@logstash:~# mkdir /logs

all’interno della quale verranno registrate tutte e tre le directory relative ai componenti del progetto.
E’ chiaro come in base alla quantità prevista di log che dovranno essere archiviati, in particolare per Elasticsearch che conterrà fisicamente le informazioni, a tale cartella potrà essere destinato più o meno spazio, dedicando all’occorrenza una partizione specifica od un mount di rete che consenta di non saturare il disco locale.

Elasticsearch: il motore di ricerca

La prima componente necessaria alla realizzazione del progetto descritto è Elasticsearch. Questo software si pone come un motore di ricerca dal veloce setup ed all’interno del quale è possibile registrare e ricercare informazioni in forma rapida e standard.
La release attuale di Elasticsearch (elasticsearch-0.20.2.tar.gz) è recuperabile presso il sito ufficiale del progetto http://www.elasticsearch.org/download/ ed è installabile mediante i seguenti semplici passi:

root@logstash:~# cd /logs
root@logstash:/logs# tar -xf /where/you/downloaded/elasticsearch-0.20.2.tar.gz

La decompressione dell’archivio ha comportato la creazione della cartella elasticsearch-0.20.2 che contiene tutto il necessario per far funzionare Elasticsearch a dovere:

root@logstash:/logs# ls elasticsearch-0.20.2
bin  config  lib  LICENSE.txt  NOTICE.txt  README.textile

Considerando di voler mantenere le configurazioni di default, funzionali agli scopi del progetto descritto, è già possibile lanciare il programma:

root@logstash:/logs# /logs/elasticsearch-0.20.2/bin/elasticsearch

Il comando dovrebbe restituire immediatamente la console dalla quale sarà possibile capire cosa sta succedendo all’interno del sistema:

root@logstash:/logs# ps -ef|grep elasticsearch
root     29924     1  0 14:48 pts/0    00:00:03 java -Xms256m -Xmx1g -Xss256k -Djava.awt.headless=true -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError -Delasticsearch -Des.path.home=/logs/elasticsearch-0.20.2 -cp :/logs/elasticsearch-0.20.2/lib/elasticsearch-0.20.2.jar:/logs/elasticsearch-0.20.2/lib/*:/logs/elasticsearch-0.20.2/lib/sigar/* org.elasticsearch.bootstrap.ElasticSearch

E’ stato quindi avviato il processo java, il cui PID 29924 può essere utilizzato per capire quali porte sono state aperte:

root@logstash:/logs# netstat -nlp | grep 29924
tcp6       0      0 :::9300                 :::*                    LISTEN      29924/java      
tcp6       0      0 :::9200                 :::*                    LISTEN      29924/java      
udp6       0      0 :::54328                :::*                                29924/java

Elasticsearch è quindi operativo e pronto a svolgere la funzione di motore di ricerca per le informazioni che verranno fornite da Logstash.

Logstash: l’accentratore di log

Tipicamente, al fine di centralizzare i log, è necessario predisporre una componente in ascolto (denominata “server”) e tante componenti client che vi scrivono (denominate “client”) quante sono le macchine di cui si necessita l’archiviazione dei log.
Nel progetto descritto la componente che permetterà di fornire una destinazione per tutti i log dalle varie locazioni di rete è Logstash.
Logstash è disponibile presso il sito ufficiale http://logstash.net/ in forma di file jar. Per predisporne al meglio l’utilizzo sarà necessario creare una cartella omonima all’interno della quale lo stesso file e le future configurazioni verranno registrate:

root@logstash:/logs# mkdir logstash
root@logstash:/logs# cd logstash
root@logstash:/logs/logstash# cp /where/you/downloaded/logstash-1.1.7-monolithic.jar .

Sebbene il file .jar di Logstash possa svolgere indifferentemente la funzione di server e client (a variarne il comportamento è la configurazione), nel setup implementato verrà predisposta una sola istanza Logstash in modalità server mentre su tutti i client per i quali si vorranno recuperare i log verrà configurato il sistema standard dei log Linux (rsyslog) affinché archivi direttamente sull’istanza Logstash.
In questo modo in primo luogo non sarà necessario configurare una componente Logstash per ciascun client, con notevole risparmio sui tempi di setup, ed inoltre le performance di tutti i client non verranno impattate in alcuna forma poiché verrà utilizzato un programma già in esecuzione quale rsyslog.

La struttura del file di configurazione di Logstash, un file di testo che potrà essere chiamato ad esempio /logs/logstash/logstash-server.conf, che verrà utilizzata inizialmente è molto semplice:

input {
       tcp {
               type => syslog
               port => 5544
       }
}
 
filter {
}
 
output { 
  elasticsearch { }
}

Analizzare le tre sezioni consente di scattare una fotografia alla sequenza di funzionamento di Logstash:

  • input: dichiara da DOVE Logstash accetterà informazioni. In questo caso viene dichiarata una tipologia di ascolto “tcp”, che corrisponde ad una modalità di servizio (syslog) e ad una porta (5544). In questa sezione è possibile ad esempio accettare input da stdin (input da terminale) o persino da twitter!
  • filter: dichiara COSA bisogna fare dei log che arrivano. Inizialmente verranno accettati indiscriminatamente tutti i log pervenuti in input alla macchina
  • filter: dichiara DOVE verranno posti i log una volta elaborati. Nel caso illustrato i log verranno passati al servizio elasticsearch (mediante la porta 9200, la default). E’ possibile ad esempio destinare i log anche ad stdout (il terminale) o addirittura direttamente a strumenti di monitor come Nagios!

Tutte le modalità operative di Logstash relative ad input, filter ed output sono descritte alla pagina http://logstash.net/docs/1.1.7/.

Terminata la creazione del file di configurazione è possibile lanciare per la prima volta Logstash:

root@logstash:/logs/logstash# nohup java -jar logstash-1.1.7-monolithic.jar agent -f logstash-server.conf &
[1] 10031
nohup: ignoring input and appending output to `nohup.out'

Nota: il comando java viene lanciato mediante nohup, che consente di mantenere in esecuzione il programma anche all’uscita dalla console.

Come nel caso di Elasticsearch per capire se logstash è avviato correttamente e risulta in ascolto alla porta 5544 come da configurazione è sufficiente lanciare i seguenti comandi:

root@logstash:/logs/logstash# ps -ef|grep logstash
root     10031  4402 24 17:10 pts/0    00:00:29 java -jar logstash-1.1.7-monolithic.jar agent -f logstash-server.conf
root     10448  4402  0 17:12 pts/0    00:00:00 grep --color=auto logstash
root@logstash:/logs/logstash# netstat -nltp | grep 10031
tcp6       0      0 :::9301                 :::*                    LISTEN      10031/java      
tcp6       0      0 :::5544                 :::*                    LISTEN      10031/java

L’output certifica quanto fatto: Logstash è in ascolto presso la porta 5544.
Per completare la configurazione di tutte le componenti interessate all’archiviazione dei log non rimane che utilizzare un client rsyslog affinché scriva i propri log all’interno dell’istanza Logstash appena configurata.
Scelta la macchina, sarà sufficiente modificarne il file /etc/rsyslog.conf aggiungendo alla fine del file la seguente direttiva:

...
...
*.* @@logstash:5544

le quale indica al sistema di dirigere tutti i messaggi di log (*.*) mediante il protocollo tcp (@@) all’host logstash (che DEVE essere un fqdn, un nome risolto correttamente dal sistema o un indirizzo IP) alla porta 5544.
Effettuando il reload del servizio rsyslog le informazioni dovrebbero cominciare ad affluire al server Logstash. E’ possibile forzare la scrittura di uno specifico log dalla macchina client in modo da avere una corrispondenza specifica per verifiche future, mediante il comando logger:

user@remote:~# logger TEST

Kibana: visualizzare e ricercare quanto registrato

Ora che il setup del motore di ricerca e del software di centralizzazione dei log è completo non rimane che capire come consultare le informazioni registrate. Il software adatto a questo scopo è Kibana, un’applicazione ruby scaricabile dal sito http://kibana.org.
Il file di archivio scaricabile dal sito dovrebbe avere un nome simile a “rashidkpc-Kibana-v0.2.0-35-g40f2512.tar.gz” e l’installazione potrà essere eseguita in due semplici passi:

root@logstash:/logs# tar -xf rashidkpc-Kibana-v0.2.0-35-g40f2512.tar.gz
root@logstash:/logs# cd rashidkpc-Kibana-v0.2.0-35-g40f2512
root@logstash:/logs/rashidkpc-Kibana-40f2512# gem install bundler
Successfully installed bundler-1.2.3
1 gem installed
Installing ri documentation for bundler-1.2.3...
Installing RDoc documentation for bundler-1.2.3...
root@logstash:/logs/rashidkpc-Kibana-40f2512# bundle install
Fetching gem metadata from http://rubygems.org/.........
Fetching gem metadata from http://rubygems.org/..
Using rake (10.0.3) 
Using daemons (1.1.9) 
Using diff-lcs (1.1.3) 
Installing eventmachine (1.0.0) with native extensions 
Installing fastercsv (1.5.5) 
Installing json (1.7.5) with native extensions 
Installing rack (1.4.1) 
Installing rack-protection (1.2.0) 
Installing tilt (1.3.3) 
Installing sinatra (1.3.3) 
Installing thin (1.5.0) with native extensions 
Installing tzinfo (0.3.35) 
Using kibana (0.0.1) from source at . 
Installing rspec-core (2.11.1) 
Installing rspec-expectations (2.11.3) 
Installing rspec-mocks (2.11.3) 
Installing rspec (2.11.0) 
Using bundler (1.2.3) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

In caso vengano segnalati errori di questo tipo:

root@logstash:/logs/rashidkpc-Kibana-40f2512# bundle install
Fetching gem metadata from http://rubygems.org/.........
Fetching gem metadata from http://rubygems.org/..
Installing rake (10.0.3) 
Installing daemons (1.1.9) 
Installing diff-lcs (1.1.3) 
Installing eventmachine (1.0.0) with native extensions 
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.
 
        /usr/bin/ruby1.8 extconf.rb 
extconf.rb:2:in `require': no such file to load -- mkmf (LoadError)
	from extconf.rb:2
 
 
Gem files will remain installed in /var/lib/gems/1.8/gems/eventmachine-1.0.0 for inspection.
Results logged to /var/lib/gems/1.8/gems/eventmachine-1.0.0/ext/gem_make.out
An error occurred while installing eventmachine (1.0.0), and Bundler cannot continue.
Make sure that `gem install eventmachine -v '1.0.0'` succeeds before bundling.

E’ presumibile che il sistema non possieda alcuni dei pacchetti necessari alla compilazione di Kibana, ad esempio su sistemi “Ubuntu Lucid” è necessario aggiungere i segeunti pacchetti:

root@logstash:/logs/rashidkpc-Kibana-40f2512# apt-get install build-essential libopenssl-ruby ruby1.8-dev

Ad installazione completata, prima di avviare Kibana, per fare in modo che il servizio sia in ascolto su tutti gli indirizzi della macchina sarà necessario modificare all’interno del file KibanaConfig.rb la seguente riga:

  KibanaHost = '127.0.0.1'

in

  KibanaHost = '0.0.0.0'

Ed infine avviare il programma con il seguente comando:

root@logstash:/logs/rashidkpc-Kibana-40f2512# ruby kibana.rb
== Sinatra/1.3.3 has taken the stage on 5601 for development with backup from Thin
>> Thin web server (v1.5.0 codename Knife)
>> Maximum connections set to 1024
>> Listening on 127.0.0.1:5601, CTRL+C to stop

Da questo momento in poi l’interfaccia Kibana sarà disponibile all’indirizzo http://logstash:5601/:

Kibana, l'interfaccia principale

Kibana, l’interfaccia principale

Mediante la casella di ricerca sarà possibile indicare cosa cercare, nel nostro caso, digitando TEST, troveremo l’occorrenza precedentemente forzata:

Kibana, il risultato di una ricerca

Kibana, il risultato di una ricerca

Il formato di ricerca è lo standard Lucene e si presta ad ogni tipo di query possibile.

Conclusioni

E’ facile capire come con questa breve panoramica l’argomento dell’archiviazione centralizzata dei log sia stato solo marginalmente sfiorato.
Esiste un’enorme quantità di varianti che possono essere applicate al sistema, in primis per quanto riguarda l’aspetto filter che non è stato trattato. E’ possibile sfruttare Logstash per assegnare tag specifici ai log selezionati, in modo da effettuare raggruppamenti, statistiche e grafici mediante Kibana.
Le evolutive sono pressoché infinite.

Nota finale sull”interfaccia nativa di logstash

Logstash possiede anche una web interface inclusa nel programma stesso, questa è attivabile mediante il seguente comando:

root@logstash:/logs/logstash# java -jar logstash-1.1.7-monolithic.jar web --backend elasticsearch:///?local

Dopo qualche secondo il programma attiverà la porta 9292 che sarà accessibile mediante il browser all’indirizzo http://logstash:9292/search:

Logstash, interfaccia web nativa

Logstash, interfaccia web nativa

Rispetto a Kibana l’interfaccia nativa risulta più essenziale ed inoltre necessita di una configurazione particolare della sezione elasticsearch di logstash (senza indicare embed => true questa non funzionerà).
La scelta su quale interfaccia risulti più utile è sempre dell’utente finale.