Le Touilleur Express

  • Accueil
  • A propos de l’auteur
  • A propos du Touilleur Express

Gestion des logs applicatifs avec Fluentd

8 octobre, 2013
Voici un retour d'expérience sur la mise en place de Fluentd avec une application Play2/Scala. Ce qui va suivre devrait intéresser n'importe quel développeur, Java ou non. Asseyez-vous et on y va.

La gestion des logs applicatifs a bien évolué, avec l’arrivée de solutions open-source intéressantes. Sur une application en prod, le volume des logs est un problème à traiter correctement. En ayant une application plutôt bien écrite, et en ne s’intéressant qu’aux erreurs et et aux warnings, cela peut cependant vite représenter un volume important d’informations à traiter.

Volume important, traitement important, tout ceci ressemble à un cas d’usage Big Data. Mais nous n’en sommes pas encore là. Voyons comment configurer une application Java (ou Scala) avec Logback, comment installer Fluentd et enfin, comment envoyer vos logs vers Amazon RDS. J’ai fait le choix de vous parler d’Amazon RDS (MySQL dans le Cloud), ce qui peut surprendre. Mais vous verrez qu’il est vraiment simple de passer à Amazon DynamoDB, ou d’utiliser une solution type SaaS comme celle proposée par Treasure Data.

Introduction

Lorsque l’on parle gestion des logs, il y a différentes étapes :

  • la collecte
  • le stockage
  • le traitement
  • la visualisation

Visualiser ses logs, c’est facile avec des solutions comme Kibana. Traiter les logs, on peut utiliser ElasticSearch ou Apache Hive lorsque vous travaillez avec Apache Hadoop ou Amazon DynamoDB. Pour le stockage donc, s’agissant d’un volume important mais qu’il faut pouvoir requêter, vous pouvez utiliser une solution type NoSQL comme Hadoop (le choix de Treasure Data) ou autre. Vous pouvez aussi utiliser MongoDB, Redis ou même une base MySQL. C’est ce choix simple que j’ai fait… pour l’instant. On peut se la raconter avec une base NoSQL, mais lorsqu’il s’agit de trier et de lancer des requêtes avancées, moi le SQL ça me plaît toujours. Je basculerai à une solution nosql le moment venu, sans que cela n’impacte mon application… Bref, si JavaEE 7 est à poil du côté logging, ici on est en plein dans les vrais problèmes de gestion des logs.

Du côté collecteur, il existe différents projets. J’ai regardé Scribe (qui vient de Facebook) puis Apache Flume. Au final, par la qualité des plugins et de la documentation, j’ai sélectionné Fluentd.

Fluentd est un projet open-source, codé en Ruby, qui permet de collecter des logs, de les structurer et ensuite de les faire suivre vers différents collecteurs. Après l’avoir installé, vous pouvez configurer un daemon TCP, UDP ou HTTP, afin de recevoir les logs venant de différentes applications. Bien entendu, Fluentd peut aussi remonter et streamer des fichiers venant de l’OS. Par exemple vos logs systèmes, des logs apache ou autre. Bref c’est un espèce de canon à électron, qui permet de collecter les logs, puis de les streamer vers différents systèmes de stockage.

Fluentd est très similaire à syslogd, sauf qu’il utilise le format JSON. Lorsque nous allons brancher notre application Java/Scala, il faudra donc émettre des trames au format JSON, pour bénéficier de toutes les fonctions de Fluentd.

Fluentd permet de brancher différents plugins, tous écrit en Ruby. L’installation d’un plugin est vraiment simple, que ce soit sur MacOS X ou sur Linux. Vous pouvez donc ajouter des plugins pour traiter les entrées (input), la gestion des buffers et enfin les flux de sortie.

Côté client, il est possible de brancher n’importe quelle technologie, que ce soit du Java, du Scala, du Ruby, du Python, du Shell… etc.

Solution pour une application Java/Scala avec logback

Ce qui suit intéressera plus les développeurs Java/Scala. Pour Zaptravel, j’ai adapté et recodé un adapteur Logback, afin de pouvoir configurer mon application avec Fluentd. Le code de l’adapteur est sur Gitub pour ceux qui sont intéressés. J’ai aussi placé mon exemple de fichier de configuration logger.xml afin de vous montrer comment cela s’utilise.

Log4J ou Logback peuvent donc envoyer les trames de log vers un serveur Fluentd. Il existe différentes solutions, rien de très compliqué à mettre en oeuvre.

Installer et configurer Fluentd

Dès la page d’accueil du projet, avec brew, yum, gem ou apt-get, vous serez pris en main pour l’installation. Sur Mac, pensez à mettre à jour votre installation de brew et XCode avant. FluentD avec un D comme Daemon, est donc un service qui écoute et qui attend de recevoir des logs. Il peut aussi surveiller des fichiers systèmes et vous faire suivre ce qui s’y passe. Ce qui serait dommage (j’ai pas dit stupide…) c’est d’écrire vos logs applicatifs dans un fichier plat… pour le relire avec FluentD et ensuite envoyer cela vers une base. Ce qui est mieux, c’est d’utiliser un appender Logback (cf paragraphe suivant) et de complètement désactiver la sortie dans votre application Java/Scala.

Fluentd s’installe sur Amazon EC2 avec apt-get :

 curl -L http://toolbelt.treasure-data.com/sh/install-ubuntu-precise.sh | sh

Une fois l’installation terminée (voir la doc ici), vous pouvez vérifier que le daemon fonctionne correctement

$ /etc/init.d/td-agent restart
$ /etc/init.d/td-agent status
td-agent (pid  21678) is running...

Il est ensuite temps d’installer un plugin afin de pouvoir envoyer vers MySQL vos logs.

 sudo /usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-mysql

La configuration de Fluentd se fait via un fichier de configuration :

 sudo vi /etc/td-agent/td-agent.conf

Dans ce fichier, nous allons déclarer une source, un adapter et un flux de sortie, ici ma base de données MySQL qui tourne quelque part dans le Cloud de la NSA :

<match amazon.rds.*>
  type mysql
  host prodlogs3.somehost.onezone.rds.amazonaws.com
  # port 3306 # default
  database application_logs
  username zaptravel
  password mon_super_password_nan_mais_oh_eh_un_
  include_time_key yes
  ### default `time_format` is ISO-8601
  # time_format %Y%m%d-%H%M%S
  ### default `time_key` is 'time'
  # time_key timekey
  include_tag_key yes
  key_names time,tag,level,thread,logger,uri,msg
  sql INSERT INTO prod (coltime,coltag,level,thread,logger,uri,msg) VALUES (?,?,?,?,?,?,?)
  flush_interval 5s
</match>

Tout message destiné à amazon.rds sera donc capté par ce matcher, qui ensuite se débrouillera pour envoyer vers Amazon RDS (MySQL in da cloud) mes messages. Voili voilou, ça c’est fait.

Après avoir relancé le daemon td-agent, puis ensuite mon application Play2/Scala, les logs applicatifs commencent à arriver.

Pour que cela fonctionne, il faut que votre fichier logger.xml soit aussi correctement configuré :

<configuration info="true" scan="false" scanPeriod="30 seconds">

    <conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel"/>

    <appender name="FLUENTD" class="org.zaptravel.logback.fluentd.FluentdLogbackAppenderBase">
        <tagprefix>amazon.rds</tagprefix>
        <clientid>Hawai05</clientid>
        <port>24224</port>
        <fluentdHost>127.0.0.1</fluentdHost>
        <maxQueueSize>1024</maxQueueSize>
    </appender>

    <logger name="play" level="WARN"/>
    <logger name="akka" level="WARN"/>
    <logger name="akka.event.slf4j.Slf4jEventHandler" level="WARN"/>
    <logger name="com.typesafe.config" level="WARN"/>
    <logger name="application-akka" level="WARN"/>

    <root level="INFO">
        <appender-ref ref="FLUENTD"/>
    </root>

</configuration>




Et c’est un peu près tout. Bon, il faut quelques connaissances unix, un peu de recherche sur le site de Fluentd, mais rien de trop compliqué.

Pourquoi c’est mieux qu’une solution de log sur le système ? 

Nous avons en général 2 machines pour la production, pour le site web. Aller lire les fichiers de logs sur le système ? Non merci, j’ai arrêté. Ensuite je vous avoue que lorsque je code, j’essaye de ne pas tartiner des logs à tout va. Je suis très pragmatique. Surtout en devenant un vieux développeur. J’essaye de blinder ce qui est fragile. Dans mon système par exemple, c’est le parsing JSON sur Redis, qui demande un peu plus d’attention. Lorsqu’un des workers écrit sur Redis, et qu’il y a un problème de format, ce qui arrive de temps en temps, ce système permet de gérer des erreurs métiers. Je fais un peu plus d’efforts dans ce cas pour donner la clé appelée, ce que le parser a lu et ce qu’il attendait.

Autre astuce de cow-boy, surtout lorsque l’on fait un site Internet, c’est le MDC.

Qu’est-ce qu’un MDC ?

Mapped Diagnostic Context, tiens tu peux lire la doc ici.

C’est un système qui permet de placer une variable de contexte, de sorte que lorsque votre système crashe, vous puissiez loguer cette valeur. Je vous sens perplexe.

Lorsque vous visitez Zaptravel, je place l’URI courante dans le MDC avec ce petit bout de code (scala ou java) :

  def home(origin: String , segment: String) = ActionWithWebuser {
    implicit context =>

      MDC.put("URL", context.request.uri)

    // fait pleins de trucs sympa.

    ...
}

Pour chaque visiteur de mon site, dans mes différentes actions, je stocke l’URI courante (et parfois les paramètres) comme diagnostic de contexte. Ceci va me permettre de loguer l’URI du visiteur lorsqu’une erreur survient. C’est vraiment très pratique.

Ensuite, pour afficher l’URI, il suffit de modifier votre fichier logger.xml et d’ajouter %X{URL} :

            %coloredLevel %d{HH:mm:ss,SSS}  %X{URL}  %logger: %message%n%ex{10}

...

Ainsi, dès lors qu’une belle et jeune exception montrera le bout de son nez, paf, vous aurez aussi l’URI utilisée par votre client. Très pratique lorsqu’il s’agit de détecter du contenu invalide sur un site web.

Une fois que l’on y a goûté, on ne peut plus s’en passer.

Côté code, je pourrais faire un article là-dessus, je crois que nous n’avons pas une seule exception Java (checked ou non) dans notre projet. Mort aux Unchecked Exceptions, surtout lorsque c’est pour faire du métier. Vous pouvez écrire « InvalidFlightException » ou « TooMuchDrinkLastNightException » ou encore « NotMyFaultException »… Mais bon… dans le monde Scala nous utilisons Options, Either ou encore Try pour gérer correctement les données incomplètes ou manquantes.

Il faudra que je vous parle de Scala un jour, c’est assez sympa.

Sur ce, je retourne coder.

Articles similaires:

Default ThumbnailGestion et surveillance de processus à distance Default ThumbnailPrésentation d’Esper, moteur de gestion de flux d’événements en Java Default ThumbnailComment simuler le navigateur de l'iphone avec Firefox ou Safari ? Default ThumbnailRetour sur le livre "Gestion de Projet Agile v3" par V.Messager Rota
  • Sebastien Lorber 19 octobre 2013 at 22 h 33 min

    Ca risque pas de poser de problèmes de faire du Play/Scala/Akka/ReactiveProgramming et du MDC en même temps?
    Dans un contexte ou on a pas un utilisateur = un thread j’entend.

Chercher

Derniers articles

  • Vis ma vie de Staff/Principal Engineer
  • Devenir Staff Engineer : comment et pourquoi ?
  • WeAreDevelopers 2022, conférence à Berlin – jour 1
  • Le chiffrement de bout en bout et la signature d’enveloppe
  • L’entretien de recrutement « System Design »

Commentaires récents

  • Nicolas Martignole dans Vis ma vie de Staff/Principal Engineer
  • Matt dans Vis ma vie de Staff/Principal Engineer
  • Sébastien dans Vis ma vie de Staff/Principal Engineer
  • BLA dans Devenir Staff Engineer : comment et pourquoi ?
  • Sébastien dans Devenir Staff Engineer : comment et pourquoi ?

Les plus lus

  • Les revenus d’un informaticien indépendant en EURL - 88 996 affichage(s)
  • Optional en Java 8 - 68 650 affichage(s)
  • Changer la batterie d’un MacBook Pro de 2011 - 64 878 affichage(s)
  • Retour sur la soirée du lundi 12 juillet chez Doctolib - 61 746 affichage(s)
  • Quelle est la différence entre volatile et synchronized ? - 60 729 affichage(s)
  • Un modèle de Product Backlog et de Sprint Backlog avec Excel - 56 046 affichage(s)
  • Redis, découverte d’un moteur clé-valeur simple et puissant - 50 225 affichage(s)
  • Comment simuler le navigateur de l'iphone avec Firefox ou Safari ? - 44 969 affichage(s)
  • serialVersionUID mythes et légendes - 41 175 affichage(s)
  • Développeur après 31 ans ? Ridé et chauve tu seras - 38 851 affichage(s)

Mots clés

agile ajax Apple architecture barcamp BarCampJavaParis ddd devoxx esb exo flex geek google grails groovy humeur humour independant iphone Java javascript jazoon jboss jboss seam jsf jug Linux mac mule paris jug parisjug pjug play playframework portlet recrutement ria Scala scrum spring Startup usi usi2010 web xebia

Derniers articles

  • Vis ma vie de Staff/Principal Engineer

    Suite de l’article précédent sur le Staff Engineer. Aujourd’hui, voyons un peu

    20 juillet, 2022
  • Inari

    Devenir Staff Engineer : comment et pourquoi ?

    Après une dizaine d’années en tant que développeur, vous serez un jour

    17 juillet, 2022
  • WeAreDevelopers 2022, conférence à Berlin – jour 1

    Il est 8h40, 19 degrés, vous êtes à Berlin. La queue dehors

    24 juin, 2022

Tweets @nmartignole

  •  @fanf42  Excellent 👌

    7 hours ago
  • RT  @iambdxoul :  @TheHackersNews  Lmao

    1 day ago
  • RT  @PR0GRAMMERHUM0R : Finally a GPT feature useful for work https://t.co/8U9FSUwKg5 https://t.co/GkUIJi7qtW

    1 day ago

Mots clés

Apple (32) Architecture (13) Big Data (5) Conference (8) Devoxx (55) Dev Web (37) Doctolib (2) geekevent (1) groovy (2) Innoteria (11) Java (517) Linux (10) Non classé (14) Perso (266) Recrutement (3) Scala (30) scrum (43) Société (3) Startup (20) Web 2.0 (67)

Le Touilleur Express

Blog par Nicolas Martignole

Contactez-moi : nicolas@touilleur-express.fr

Suivez-moi sur Twitter : @nmartignole

Copyright© 2008 - 2020 Nicolas Martignole | Tous droits réservés
  • A propos de l’auteur
  • A propos du Touilleur Express
  • Log In
  • My Account
  • My Profile
  • Reset Password

Le Touilleur Express