Gestion des logs avec Graylog

Introduction

Graylog2 va permet d’avoir une gestion des logs centralisée. Ces logs seront stockés dans une base de données Elasticsearch. Les paramètres de Graylog2 seront quand à eux stockés dans Mongodb. Et pour finir nous pourront gérer ces logs via une interface graphique faite en Ruby qui se nomme graylog2-web-interface.

Site officiel

Vous trouverez le site officiel de Graylog à l’adresse suivante : http://www.graylog2.org/

Tutoriel

Avant d’entamer ce tutoriel, vérifiez que vous ayez bien les pré requis :

      • Le JDK doit être installé sur votre machine.
      • Toutes les installations sont faites dans /opt/.

Installation

Installation Serveur

Installation de Elasticsearch

Elasticsearch Permet de stocker nos logs.
Commande a effectuer :
wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.18.7.tar.gz

tar xzf elasticsearch-0.18.7.tar.gz
mv elasticsearch-0.18.7 /opt/elasticsearch

Configuration :

Allez dans le fichier /opt/elasticsearch/config/elasticsearch.yml on va donner un nom plus explicite à la base et mettre l’adresse ici ce sera localhost.
cluster.name: logcentral

network.host: localhost
Pour poursuivre la configuration allez sur : http://www.elasticsearch.org/tutorials/2010/07/02/setting-up-elasticsearch-on-debian.html ou continuez ce tutoriel.
Créez le fichier dans /etc/init.d/elasticsearch

Le document doit comporter ces lignes :

#! /bin/sh
### BEGIN INIT INFO
# Provides:          elasticsearch
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts elasticsearch
# Description:       Starts elasticsearch using start-stop-daemon
### END INIT INFO
 
ES_HOME=/opt/elasticsearch
ES_MIN_MEM=256m
ES_MAX_MEM=2g
DAEMON=$ES_HOME/bin/elasticsearch
NAME=elasticsearch
DESC=elasticsearch
PID_FILE=/var/run/$NAME.pid
LOG_DIR=/var/log/$NAME
DATA_DIR=/var/lib/$NAME
WORK_DIR=/tmp/$NAME
CONFIG_FILE=/opt/$NAME/config/elasticsearch.yml
DAEMON_OPTS="-p $PID_FILE -Des.config=$CONFIG_FILE -Des.path.home=$ES_HOME -Des.path.logs=$LOG_DIR -Des.path.data=$DATA_DIR -Des.path.work=$WORK_DIR"
 
test -x $DAEMON || exit 0
 
set -e
 
case "$1" in
  start)
    echo -n "Starting $DESC: "
    mkdir -p $LOG_DIR $DATA_DIR $WORK_DIR
    if start-stop-daemon --start --pidfile $PID_FILE --startas $DAEMON -- $DAEMON_OPTS
    then
        echo "started."
    else
        echo "failed."
    fi
    ;;
  stop)
    echo -n "Stopping $DESC: "
    if start-stop-daemon --stop --pidfile $PID_FILE
    then
        echo "stopped."
    else
        echo "failed."
    fi
    ;;
  restart|force-reload)
    ${0} stop
    sleep 0.5
    ${0} start
    ;;
  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|force-reload}" >&2
    exit 1
    ;;
esac
 
exit 0

Faire attention si vous avez installé Elasticsearch dans un autre répertoire que /opt les variables suivantes changeront :
ES_HOME, CONFIG_FILE
Pour finir on installe le script :

chmod +x /etc/init.d/elasticsearch
update-rc.d elasticsearch defaults

On démarre le service :

sudo /etc/init.d/elasticsearch start

Installation de MongDB

Pour commencer il faut exécuter la commande suivante pour importer le 10gen clé publique GPG :

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10

Puis il faut mettre le lien de téléchargement du package dans /etc/apt/source.list.d/10gen.list
deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen
Après il faut faire un update du repository :

sudo apt-get update

Et pour finir on installe MongoDB :

sudo apt-get install mongodb18-10gen

Lancement de MongoDB :

sudo service mongodb start

Et pour que l’installation soit utilisable il faut la paramétrer.

~$ mongo
 
> use graylog2
 
>db.addUser('graylog-user', 'grayloguser-mongo-passwd')

Installation graylog2-server

On récupère l’archive, la décompresse :

cd /opt/
 
wget <a href="https://github.com/downloads/Graylog2/graylog2-server/graylog2-server-0.9.6p1.tar.gz"> https://github.com/downloads/Graylog2/graylog2-server/graylog2-server-0.9.6p1.tar.gz</a>
 
tar zxvf graylog2-server-0.9.6p1.tar.gz
 
sudo mkdir /opt/graylog2
sudo cp -r graylog2-server-0.9.6p1 /opt/graylog2/server
sudo chown -R nom:nom /opt/graylog2

Puis mettre le fichier de configuration dans /etc :

sudo cp /opt/graylog2/server/graylog2.conf.example /etc/graylog2.conf

Maintenant nous allons paramétrer le serveur pour qu’il communique avec Elsaticsearch et MongoDB.

Dans le graylog2.conf mettre ces valeurs :

# ElasticSearch URL (default: http://localhost:9200/)
elasticsearch_url = http://localhost:9200/
elasticsearch_index_name = logcentral
 
# MongoDB Configuration
mongodb_useauth = true
mongodb_user = graylog-user
mongodb_password = grayloguser-mongo-passwd
mongodb_host = localhost
#mongodb_replica_set = localhost:27017,localhost:27018,localhost:27019
mongodb_database = graylog2
mongodb_port = 27017
mongodb_max_connections = 500

Passons maintenant au fichier de lancement dans /etc/init.d avec un fichier graylog2-serveur

#!/bin/sh
#
# graylog2-server:   graylog2 message collector
#
# chkconfig: - 98 02
# description:  This daemon listens for syslog and GELF messages and stores them in mongodb
#
 
CMD=$1
NOHUP=`which nohup`
JAVA_HOME=/opt/jdk
JAVA_CMD=$JAVA_HOME/bin/java
 
GRAYLOG2_SERVER_HOME=/opt/graylog2/server
 
start() {
	echo "Starting graylog2-server ..."
	$NOHUP $JAVA_CMD -jar $GRAYLOG2_SERVER_HOME/graylog2-server.jar > /var/log/graylog2.log 2>&1 &
}
 
stop() {
	PID=`cat /tmp/graylog2.pid`
	echo "Stopping graylog2-server ($PID) ..."
	kill $PID
}
 
restart() {
	echo "Restarting graylog2-server ..."
	stop
	start
}
 
case "$CMD" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo "Usage $0 {start|stop|restart}"
RETVAL=1
esac

Dans /etc/logrotate.d créez un fichier graylog2-serveur

/var/log/graylog2.log {
daily
rotate 90
copytruncate
delaycompress
compress
notifempty
missingok
}

Pour finir nous allons lancer graylog2-serveur :

chmod +x /etc/init.d/graylog2-server
sudo service graylog2-server start

Installation interface

Commençons par télécharger l’interface et à l’installer :

wget --no-check-certificat
<a href="https://github.com/downloads/Graylog2/graylog2-web-interface/graylog2-web-interface-0.9.6p1-RC2.tar.gz">https://github.com/downloads/Graylog2/graylog2-web-interface/graylog2-web-interface-0.9.6p1-RC2.tar.gz</a>
tar xzf graylog2-web-interface-0.9.6p1-RC2.tar.gz
 
sudo cp -r graylog2-web-interface-0.9.6p1-RC2 /opt/graylog2/web
 
sudo chown -R graylog:graylog /opt/graylog2
 
cd /opt/graylog2/web
 
sudo gem install bundler
 
sudo bundle install

Puis nous allons modifier la configuration dans /opt/graylog2/web/config.
Pour le fichier mongoid.yml :

# Use environment variables
#production:
#  host: <%= ENV['MONGOID_HOST'] %>
#  port: <%= ENV['MONGOID_PORT'] %>
#  username: <%= ENV['MONGOID_USERNAME'] %>
#  password: <%= ENV['MONGOID_PASSWORD'] %>
#  database: <%= ENV['MONGOID_DATABASE'] %>
 
# or specify values manually
production:
host: localhost
port: 27017
username: graylog-user
password: grayloguser-mongo-passwd
database: graylog2
 
# Values below are for development and testing.
# You may comment out them or just ignore.
 
development:
host: localhost
port: 27017
username: graylog-user
password: grayloguser-mongo-passwd
database: graylog2
 
test:
host: localhost
database: graylog2_test

Et pour le fichier indexer.yml :

production:
url: http://localhost:9200/
index_name: logcentral

Faire la commande suivante pour paramétrer l’environnement :

RAILS_ENV=production script/rails server

Pour finir il faut créer un hôte virtuel. Pour se faire, créez un fichier graylog2 dans /etc/apache2/sites-available/ et mettre la configuration suivante :

<VirtualHost *:80>
 
   ServerName      graylog2.monitoring-fr.org
   ServerAlias     *.graylog2.monitoring-fr.org
 
   ServerAdmin root@iojo.net
   DocumentRoot /opt/graylog2/web/public
 
   <Directory /opt/graylog2/web/public>
   Allow from all
   Options -MultiViews
   </Directory>
 
   ErrorLog /var/log/apache2/error.log
   LogLevel warn
   CustomLog /var/log/apache2/access.log combined
</VirtualHost>

Il ne reste plus qu’à activer l’hôte et redémarrer apache2 :

sudo a2ensite graylog2.monitoring-fr.org
sudo /etc/init.d/apache2 restart

Maintenant vous pouvez lancer l’interface en lançant ces commandes :

cd /opt/graylog2/web
script/rails server -e production

Si vous voulez avoir plus de possibilité pour les recherches de logs, modifiez les fichiers suivants comme ci dessous :

Dans /opt/graylog2/web/app/model/message_gateway.rb ajoutez :

# Full message
 
must { string("full_message:#{filters[:full_message]}") } unless filters[:full_message].blank?

Dans /opt/graylog2/web/app/views/messages/_quickfilter.hmtl.erb :

<dt><%= label_tag "filters[:full_message]", "Full Message:" %></dt>
<dd><%= text_field_tag "filters[full_message]", params[:filters].blank? ? nil : params[:filters][:full_message] %> <%=raw tooltip("Message-search-syntax") %></dd>

Voici maintenant des explications pour utiliser le moteur de recherche. Celles-ci concernent es trois premiers champs car ils ne sont pas facile à comprendre.

Pour les parties messages et full message il est possible de faire des recherches approximatives. En faisant « roam~ » devant le mot ou groupe de mots inséré. On peut également mettre « * » à la fin. Voici un lien qui explique toutes les autres possibilités : https://github.com/Graylog2/graylog2-web-interface/wiki/Message-search-syntax

En ce qui concerne la partie Timeframe voici comment écrire les valeurs de recherche :

      • from 20 minutes ago
      • from 20 minutes ago to now
      • from 20 minutes ago to ten minutes ago
      • from last month
      • from last month to 1 week ago
      • from 2011-06-08
      • from 2011-06-01 12:00:00 to 2011-06-08 12:00:00

Je vous indique également un lien qui vous expliquera toutes les autres possibilités de Timeframe : https://github.com/Graylog2/graylog2-web-interface/wiki/Timeframe-Filters

Si vous voulez, par exemple, supprimer les logs :

curl -XDELETE '<a href="http://localhost:9200/logcentral/">http://localhost:9200/logcentral/</a>'

Création du projet dans Eclipse

      • Lancer Eclipse.
      • File → New → Other → Maven Project.
      • La fenêtre de wizard apparaît alors. Nous allons simplement indiquer ici le nom du projet dans le champ Project name : sf-tutorial-graylog
      • Cliquer sur Finish. Le projet apparaît alors dans l’onglet Package qui répertorie les différents projets du workspace.
      • Dans le dossier src/main/java il faut créer un package : Clic droit sur le dossier →New → Package → com.scub.foundation.tutorial.graylog

Nous allons créer les classes nécessaires pour notre test :

Calculette.java

package com.calculette.core.service;
 
/**
 * Service de calculette.
 * @author Scub Foundation
 */
public interface Calculette {
 
    /**
     * Additionne deux entier.
     * @param a Permier nombre
     * @param b Deuxieme nombre
     * @return La somme de {@code a} et {@code b}.
     */
    Integer additionner(Integer a, Integer b);
 
}

SimpleCalculette.java

package com.calculette.core.service;
 
import org.apache.log4j.Logger;
 
/**
 * Implementation simple du service de calculette.
 * @author Scub Foundation
 */
public class SimpleCalculette implements Calculette {
 
    private final Logger logger = Logger.getLogger(this.getClass());
 
    /**
     * {@inheritDoc}
     */
    public Integer additionner(Integer a, Integer b) {
        logger.debug("=============================> Additionner");
        // REGLE CAL_RG_001.1 La fonction doit emettre une erreur si un des
        // parametres est <code>null</code>
        Util.checkNotNullOrThrowIAE(a, "Le param a ne peut pas etre null");
        Util.checkNotNullOrThrowIAE(b, "Le param b ne peut pas etre null");
 
        // CAL_RG_001 La fonction additionne deux entiers.
        logger.info("=============================> Résultat : " + (a + b));
        return a + b;
    }
 
}

Util.java

package com.calculette.core.service;
 
/**
 * Quelques utilitaires en vrac.
 * @author Scub Foundation
 */
public class Util {
 
    /**
     * Ensures that an object reference passed as a parameter to the calling method is not null.
     * @param reference an object reference
     * @param errorMessage the exception message to use if the check fails; will be converted to a string using {@link String#valueOf(Object)}
     * @return the non-null reference that was validated
     */
    public static T checkNotNullOrThrowIAE(T reference, Object errorMessage) {
        if (reference == null) {
            throw new IllegalArgumentException(String.valueOf(errorMessage));
        }
        return reference;
    }
}

Puis dans src/test/java, ajout un nouveau package → Clic droit sur le dossier → New → Package → com.scub.foundation.tutorial.graylog.test
Et il faut également créer des classes au niveau de ce package.

AbstractCalculetteTest.java

package com.calculette.core.test;
 
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
import com.calculette.core.service.Calculette;
 
/**
 * Tests de la calculette REGLE CAL_RG_001.a, CAL_RG_001.b, CAL_RG_001.1.a, CAL_RG_001.1.b.
 * @author Thierry Leriche-Dessirier
 */
public abstract class AbstractCalculetteTest {
 
    /** Calculette. */
    protected Calculette calculette;
 
    /**
     * Test.
     * PARAM nombre1 = 1 
     * PARAM nombre2 = 2 
     * RESULT = 3
     */
    @Test
    public void testCalcul1() {
        // Arrange
        final Integer nombre1 = 1;
        final Integer nombre2 = 2;
 
        final Integer expected = 3;
 
        // Act
        doTest_CAL_RG_001xxx(nombre1, nombre2, expected);
    }
 
    /**
     * Test.
     * PARAM a = 1 
     * PARAM b = -1 
     * RESULT = 0
     */
    @Test
    public void testCalcul2() {
        // Arrange
        final Integer nombre1 = 1;
        final Integer nombre2 = -1;
 
        final Integer expected = 0;
 
        // Act
        doTest_CAL_RG_001xxx(nombre1, nombre2, expected);
    }
 
    /**
     * Test.
     * PARAM a = 1 
     * PARAM b = null 
     * RESULT = IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public void testCalculFaux() {
        // Arrange
        final Integer nombre1 = 1;
        final Integer nombre2 = null;
 
        // Act
        doTest_CAL_RG_001xxx(nombre1, nombre2, null);
    }
 
    /**
     * Test.
     * PARAM a = null 
     * PARAM b = 2 
     * RESULT = IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public void testCalculFaux2() {
        // Arrange
        final Integer nombre1 = null;
        final Integer nombre2 = 2;
 
        // Act
        doTest_CAL_RG_001xxx(nombre1, nombre2, null);
    }
 
    private void doTest_CAL_RG_001xxx(Integer nombre1, Integer nombre2, Integer expected) {
        // Act
        final Integer result = calculette.additionner(nombre1, nombre2);
 
        // Assert
        assertEquals(expected, result);
    }
 
}

SimpleCalculetteTest.java

package com.calculette.core.test;
 
import org.junit.Before;
import com.calculette.core.service.SimpleCalculette;
 
/**
 * Test de SimpleCalculette.
 * @author Scub Foundation
 */
public class SimpleCalculetteTest extends AbstractCalculetteTest {
 
    @Before
    public void doBefore() {
	calculette = new SimpleCalculette();
    }
 
}

Nous allons maintenant nous attaquer au fichier log4J. Ce fichier va être changé entièrement, les logs seront passés à log4J, Gelf va permettre de faire le pont avec graylog2.

Voici comment est formé un fichier log4J.properties :

# Define the graylog2 destination
log4j.appender.graylog2=org.graylog2.log.GelfAppender
log4j.appender.graylog2.graylogHost=localhost
log4j.appender.graylog2.originHost=scub-foundation
log4j.appender.graylog2.facility=socle-core
log4j.appender.graylog2.layout=org.apache.log4j.PatternLayout
log4j.appender.graylog2.extractStacktrace=true
log4j.appender.graylog2.addExtendedInformation=false
log4j.appender.graylog2.additionalFields={'environment': 'TEST', 'application': 'TestSocle'}
 
# Send all INFO logs to graylog2
log4j.rootLogger=INFO, graylog2
 
log4j.logger.com.calculette.core.service=DEBUG

Explication sur les variables utilisées.

log4j.appender.graylog2 : Ceci permet de dire que c’est GelfAppender qui fait le pont entre log4J et graylog2.

log4j.appender.graylog2.graylogHost : C’est l’adresse IP de graylog2.

log4j.appender.graylog2.originHost : Permet de dire sur quel poste les logs ont été mis.

log4j.appender.graylog2.facility : Cette variable peut définir, de quel projet viens les logs.

log4j.appender.graylog2.extractStacktrace : Ajout des stacktraces aux messages Gelf.

log4j.appender.graylog2.addExtendedInformation : Permet d’ajouter des informations de Log4j NDC/MDC.

log4j.appender.graylog2.additionalFields : On définit l’environnement et l’application.

Pour plus d’informations voici un lien utile : https://github.com/t0xa/gelfj

La prochaine étape consiste à importer la librairie maven gelfj.

Téléchargez cette librairie en version 0.91 à partir de ce lien : https://github.com/t0xa/gelfj/downloads. Puis exécuter la commande suivante depuis l’emplacement du fichier téléchargé :

mvn install:install-file -DgroupId=org.graylog2 -DartifactId=gelfj -Dversion=0.9.1-SNAPSHOT -Dpackaging=jar -Dfile= EmplacementDuJAR/gelfj-0.9.1.jar

La dernière étape consiste à modifier le fichier pom.xml :

<dependency>
        <groupId>org.graylog2</groupId>
        <artifactId>gelfj</artifactId>
        <version>0.9.1-SNAPSHOT</version>
</dependency>

Si vous avez un problème avec Json, modifiez le fichier POM.xml avec les lignes suivantes :

<dependency>
	<groupId>com.googlecode.json-simple</groupId>
	<artifactId>json-simple</artifactId>
	<version>1.1</version>
</dependency>

Une fois les services démarrés, lancez les tests et allez sur l’interface de Graylog (localhost:3000) voici le résultat que vous devriez avoir :

Télécharger les sources

Les sources du projet Eclipse pour ce tutoriel sont téléchargeables sur Source Forge à l’adresse suivante.