Logstash et MongoDB en 10 minutes

Lorsqu'il s'agit de mettre en place des outils de gestion de logs applicatifs, Logstash est souvent mis en avant.

Il est souvent proposé en combinaison avec d'autres utilitaires comme ElasticSearch et Kibana, qui, bien que remarquables, posent deux soucis :

  1. l'effet "usine à gaz" : en effet, 3 outils à prendre en main d'un coup et à déployer, cela peut paraître intimidant.
  2. "Quels sont mes besoins ?" : ces outils sont essentiellement destinés à la création/analyse de statistiques extraites des informations loggées.

Dans l'exemple que j'ai choisi ici, la structure des fichiers de logs ne permet pas ce genre d'utilisation : en effet, une ligne de log en elle-même ne comporte que peu d'information (entrée dans un service, appel d'une procédure stockée...). Mais c'est plutôt en ensemble de lignes qui permet de reconstituer un scénario dans l'application : ce que l'utilisateur a fait, par où est passé le code, etc. En somme une analyse contextuelle (verticale) des logs plutôt que du contenu (horizontale).

Nous allons donc voir comment il est tout de même possible d'utiliser Logstash et MongoDB pour créer une application facilitant l'analyse de fichiers de logs volumineux.

Tout d'abord, pourquoi ces outils?

Logstash : il est prévu pour traiter des volumes de données importants, de manière efficace, même pour des fichiers au contenu spécifique grâce à son moteur d'expressions régulières Grok. Sa configuration est également très simple car il embarque des composants tout prêts, comme l'accès aux bases MongoDB.

MongoDB : NoSQL pour une mise en place rapide (schemaless orientée document), sans configuration, gérant également des grands volumes de données (au format JSON, utile pour les applis web).

C'est parti, mise en place!

Logstash

Il se présente sous la forme d'un Jar autonome exécutable et ne nécessite qu'un fichier de configuration. En voici un exemple, l'explication par la suite :


input {
  file {
    type => "serveur"
    path => "C:/log/serveur_*.log"
  }

  file {
    type => "client"
    path => "C:/log/client_*.log"
  }
}

filter {
  grok {
    match => [ "message", "%{DATESTAMP:date} %{LOGLEVEL:level} ?(<context>[a-Z0-9_]*) %{GREEDYDATA:message}" ]
  }
}

output {
  mongodb {
    collection => "collec-%{type}"
    database   => "local"
    uri        => "mongodb://localhost"
  }
}

En détails :

  • Les entrées (input) de type "fichier" :
    • type : une étiquette qui permet de différencier nos sources de fichiers (logs serveur d'un côté et client de l'autre)
    • path : le chemin d'accès, utilisant des wildcards
  • filter : la traitement a effectuer sur les entrées, ici un découpage via une expression régulière Grok
    • %{DATESTAMP:date} : on crée un champ nommé "date" constitué d'un timestamp, quel que soit le format (trop fort!)
    • %{LOGLEVEL:method} : un champ nommé "level" contenant les constantes classique de niveau de log : INFO, ERROR...
    • ?(<context>[a-Z0-9_]*) : un champ nommé "context" basé sur une expression régulière personnalisée
    • %{GREEDYDATA:message} : un champ nommé "message" contenat... tout et n'importe quoi!
  • Les sorties (output) de type "mongodb", avec les infos de connexion basiques. Petite astuce : il est possible de rendre dynamiques les éléments de configuration pour chaque ligne de log traitée.

Il est possible de se faciliter l'écriture de l'expression Grok avec Grok Debugger. Comme vous le voyez, très efficace!

Ces quelques lignes placées dans un fichier "ma-config.conf", Logstash se lance simplement avec :

java -jar logstash-1.3.2-flatjar.jar agent -f ma-config.conf

MongoDB

Là, rien de plus simple (la doc ici) :

  1. Lancer "mongod.exe" pour démarrer la base
  2. Optionnel : lancer "mongo.exe" pour ouvrir la console d'administration
  3. Dans notre exemple, pas besoin de créer une base de données, "local" est déjà créée par défaut.

Et voilà! Vous pouvez d'ores-et-déjà déposer des fichiers dans les répertoires indiqués, Logstash va lancer nos traitements pour fournir les documents correspondant dans notre base...

Comme je vous sens coupé dans votre élan, allons plus loin.

API Java

Bien évidemment, MongoDB vient avec une API Java très simple d'utilisation. Quelques lignes de code déployées par exemple sur un serveur Glassfish exposant des webservices REST via Jersey et vous avez une application web pour consulter et requêter dans vos fichiers de logs!

Petits exemples, avec JQuery datatables et un tableau de bord avec gridster :

Plus loin...

Ils vous est également possible de pousser un peu plus loin ce système en utilisant cette extension de log4j, log4mongo, afin d'écrire vos logs en temps réel dans la base MongoDB depuis votre application!


Fichier(s) joint(s) :



Introduction au NoSQL avec Apache CouchDB

Je vais vous montrer comment prendre en main facilement une base de données NoSQL, grâce à un exemple simple.

Nous allons créer une petite application utilisant Ektorp, une API de mapping par annotations et CouchApp, un utilitaire pour déployer des applications HTML5.

Création des données

Pour commencer, il suffit de créer un simple POJO représentant un objet métier. Comme illustré dans la documentation Ektorp ici, il n'est même pas nécessaire de mapper les attributs à enregistrer. C'est même le contraire, Ektorp part du principe que tous les attributs seront sauvegardés sauf ceux explicitement annotés comme ignorés! Un bon gain de temps...

Ensuite, quelques lignes suffisent pour implémenter les fonctionnalités primaires de CRUD :

Here's how a SofaRepository implemented with the generic repository looks like

public class SofaRepository extends CouchDbRepositorySupport {

    public SofaRepository(CouchDbConnector db) {
        super(Sofa.class, db);
    }

}

This repository will have the following methods "out of the box":

SofaRepository repo = new SofaRepository(db);

repo.add(Sofa s);
repo.contains("doc_id");
Sofa sofa = repo.get("doc_id");
repo.update(Sofa s);
repo.remove(Sofa s);
List repo.getAll();

A ce stade, nous avons déjà de quoi mettre en place une moulinette pour insérer des données. Une fois ceci fait, il est possible de consulter le contenu de la base avec Futon, une interface web fournie par CouchDB, à l'adresse http://localhost:5984/_utils/ :

Initier l'application web

CouchDB propose une interface REST très pratique. Ce qui signifie que n'importe quel outil effectuant des requêtes HTTP peut interroger directement la base, y compris un navigateur et... Ajax!

Seulement, comme certains yeux affûtés l'auront remarqué, CouchDB démarre par défaut sur le port 5984, ce qui rend impossible les accès directs via Ajax, par raison de sécurité. Si vous n'avez pas la main sur le serveur hébergeant la base afin de configurer le mécanisme HTTP "CORS", comme indiqué sur cette page, il vous faudra passer par CouchApp afin de déployer votre application sur le serveur interne de CouchDB (comme c'est le cas de Futon).

Un tutoriel très concis explique comment générer et déployer une application basique :

En réalité, tous le fichiers composant cette application sont des documents au sens NoSQL que CouchDB gère comme tels. Tous les fichiers "statiques" (images, css, js...) sont des "_attachments".

Lister les documents

Imaginons que nos documents possèdent un attribut "date", par lequel nous voulons les filtrer, entre une date de début et une de fin.

Nous allons commencer par créer une vue, qui va nous retourner la liste des documents identifiés par une clé issue de notre champ "date".

Ceci se fait par l'intermédiaire des fonctions view, fonctions Javascript pures appelées pour chaque document, pouvant servir de filtre (le cas échéant). Créons par exemple un fichier "by_date.js" dans le répertoire "/views/by_date/" de notre application. Voici donc un exemple de ce que nous cherchons :


function(doc) {
        if(doc.date) {
                emit(doc.date,doc);
        }
} 

Le résultat de notre fonction est accessible à l'adresse (objets JSON) : GET /[db]/_design/[appName]/_view/by_date/

{
  "total_rows": 2,
  "offset": 0,
  "rows": [
    {
      "key": "2014/01/15 15:52:20",
      "value": {...}
    },

    {
      "key": "2014/01/30 18:04:11",
      "value": {...}
    }

  ]
}

Utiliser JQuery

Maintenant nous pouvons compléter le fichier "index.html" (situé dans "_attachments") afin d'ajouter des fonctionnalités. Mais il faut savoir que CouchDB dispose d'un plugin JQuery pour faciliter les interactions. Par exemple, pour interroger notre vue :


$.couch.db("[db]").view("[appName]/by_date", {
    success: function(data) {
        console.log(data);
    },
    error: function(status) {
        console.log(status);
    }
});

Enfin, pour ajouter simplement des filtres sur les dates, il suffit d'intégrer les mots clés : "[appName]/by_date?startkey=[date1]&endkey=[date2]"

Ainsi, avec REST et HTML5/Javascript, vous voilà équipé pour jouer avec CouchDB! :) Enjoy!

Sources :


Fichier(s) joint(s) :