Introduction au monitoring d’une application Symfony2

Ce billet n’est pas sponsorisé par Elastic ou NewRelic.

Au-delà du développement d’une application Symfony2, notre mission au sein de JoliCode est également de mettre en place les outils qui vont permettre à nos clients de s’assurer que leurs applications fonctionnent et tiennent la charge.

L’objectif de ce billet est de présenter quelques outils ou configurations utilisés sur la plupart de nos projets pour monitorer au mieux un projet Symfony2. Si vous naviguez autour de la sphère DevOps ou si vous suivez les conférences de l’AFUP, vous n’apprendrez sûrement pas grand chose.

Les outils

Le monitoring de nos applications passe au minimum par 2 services : ELK et NewRelic.

ELK (Elasticsearch Logstash Kibana)

ELK est une stack qu’on ne présente plus. C’est la combinaison de trois outils :

  • Elasticsearch pour le stockage des informations ;
  • Logstash pour le traitement et l’analyse des logs ;
  • Kibana pour la visualisation (Dashboard).

À noter qu’Elastic a annoncé récemment un rewording complet de sa stack, il faudra bientôt parler de Elastic Stack à la place de ELK.

Logstash est le nœud central qui va s’occuper de recevoir les logs depuis les différents composants de votre projet (serveur Web, application, base de données, …). Il va être capable de recevoir des données à partir de différentes sources (Syslog, Gelf, RabbitMQ, …), les traiter, les transformer puis les stocker dans Elasticsearch.

Logstash est écrit en JRuby, implémentation de l’interpréteur de Ruby en Java. Il est réputé pour être gourmand en ressources. Dans la plupart des cas simples, il répondra à votre besoin. En cas de fortes charges, il faudra parfois lui adjoindre un buffer (RabbitMQ, Redis, …).

Si vous cherchez des solutions moins gourmandes en ressources, sachez qu’il existe des alternatives :

NewRelic

NewRelic est une solution de monitoring dans le cloud qui permet de rapidement collecter des informations sur votre application (temps de réponse moyen, …). Il existe des agents ou des plugins pour la plupart des technologies :

  • l’agent serveur collecte des informations sur le CPU, le Load Average, l’occupation des disques, …
  • l’agent PHP peut récupérer des informations sur les scripts PHP les plus appelés, les temps de réponse moyens, les exceptions,

La version gratuite limite la rétention des données à 24h.

La version payante vous permettra de conserver les données durant plusieurs jours, d’avoir accès à la pile d’exécution de vos scripts (Stack Trace), de connaître les requêtes lentes, ou d’interagir avec l’API (notification lors des déploiements par exemple).

C’est une solution qui est simple à mettre en œuvre et vous permettra d’avoir rapidement des informations sur le fonctionnement de votre application.

Envoi des logs Nginx à ELK (Elasticsearch Logstash Kibana)

Un projet Symfony est souvent composé d’un ou plusieurs serveurs Web (Nginx). Les logs d’accès (access_log) contiennent des informations précieuses (404, 500, …) que nous aimons analyser. ELK va nous permettre de centraliser ces logs dans un outil commun.

Une solution simple pour le mettre en place est de configurer Logstash pour écouter sur un port Syslog et de configurer Nginx afin qu’il ne stocke pas les logs sur le disque mais qu’il les envoie à Logstash via Syslog.

La configuration Logstash est assez simple :

input {
    syslog {
       port => 10514
       type => "syslog"
    }
}

Nous configurons Logstash pour écouter sur le port 10514 et nous lui indiquons que les données reçues seront de type Syslog. Le port 10514 est totalement arbitraire. Cela ne correspond pas au port Syslog par défaut (514) que nous laissons pour le système.

Vous pourrez ensuite configurer Nginx afin qu’il envoie ses logs via Syslog. Quelque chose comme ça devrait faire l’affaire :

error_log syslog:server=logstash-server.domain.com:10514;
access_log syslog:server=logstash-server.domain.com:10514 combined;

en remplacement du classique :

error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log combined;

Les logs seront envoyés en UDP sur Logstash.

Afin de pouvoir créer de beaux tableaux de bord dans Kibana, vous pouvez également ajouter des filtres grok afin de parser correctement les logs d’accès de nginx :

filter {
if [type] == "syslog" {
  if [program] == "nginx" {
      grok {
        match => { "message" => "%{IPORHOST:nginxhost} %{COMBINEDAPACHELOG}" }
      }

      if [nginxhost] {
         mutate {
             replace => [ "host", "%{nginxhost}" ]
             remove_field => "nginxhost" # prune the field after successfully replacing "host",
          }
        }

        geoip {
           source => "clientip"
        }
    }
}
}

Je passe rapidement sur la partie sauvegarde dans Elasticsearch. Il y a plusieurs techniques selon la charge que vous devez supporter. Une solution basique est :

output {
  elasticsearch_http {
    host => "localhost"
    port => 9200
  }
}

Grâce à cette configuration, vos logs d’accès Nginx seront transmis à Logstash qui les stockera dans un bel Elasticsearch ♥ et vous pourrez rapidement créer un dashboard dans Kibana.

http://jolicode.com/media/original//2016/nginx-log.png

Syslog est ton ami

Dans le même ordre d’idée, vous pouvez également utiliser Syslog pour router tout type de log vers une autre machine (et donc Logstash). Par exemple, MongoDB est capable d’écrire ses logs dans Syslog.

Si vous souhaitez envoyer vos logs à Logstash, vous pouvez utiliser une configuration de ce type dans /etc/rsyslog.d/ :

:programname, contains, "mongod" @logstash-server.domain.com:10514
:programname, contains, "mongod" /var/log/mongodb/mongod.log
&~

Tous les logs reçus dans Syslog pour le programme mongod seront à la fois envoyés en UDP (notez le simple @, utilisez @@ pour du TCP) au serveur Logstash et stockés localement sur le disque dans le fichier /var/log/mongodb/mongod.log.

Mongo Dashboard

Cette technique peut être utilisée pour beaucoup d’autres applicatifs afin de centraliser les logs dans ELK.

Envoi des logs Symfony2 à ELK via Gelf

Envoyer les logs Nginx à ELK, c’est bien mais nous pouvons également envoyer les logs Symfony2. Olivier Dolbeau de Blablacar a, à plusieurs reprises, expliqué ce mécanisme.

La mise en œuvre est à nouveau également assez simple si on utilise le handler GELF de Logstash. GELF est un format propriétaire de Graylog (un concurrent de Logstash) qui permet d’envoyer à travers le réseau des trames de logs.

L’intérêt de cette solution est qu’elle est assez rapide à mettre en œuvre avec Monolog.

La première étape consiste à configurer Logstash afin de lui indiquer qu’il doit supporter l’entrée de données via Gelf.

input {
    gelf {
        type => gelf
    }
}

Cette configuration va ouvrir un port 12201 (port par défaut de gelf) qui sera utilisé pour transmettre les trames de logs de Symfony2.

Vous pouvez ensuite configurer Monolog afin de lui indiquer de ne plus créer de fichiers sur le disque mais d’envoyer les logs à Logstash (via Gelf, si vous suivez).

monolog:
    handlers:
...
        gelf:
            type: gelf
            publisher:
                hostname: %logstash_gelf_host%
                port: %logstash_gelf_port%
            level: info

Vous aurez au préalable ajouté dans votre composer.json une dépendance au handler gelf pour monolog :

"graylog2/gelf-php": "~1.1",

Vos logs seront ensuite transmis à ELK et vous pourrez faire de beaux dashboards. N’oubliez pas d’utiliser les variables de contexte dans monolog. Ces variables de contexte seront automatiquement converties et présentes dans Elasticsearch.

$this->logger->info('update photo', ['id' => $id]);

Ici, ['id' => $id] est une variable de contexte. Elle sera accessible dans Elasticsearch via ctxt_id.

Si vous utilisez des channels monolog dédiés, le nom du channel sera automatiquement envoyé à Gelf et sera présent dans la variable facility.

Monitoring avec NewRelic

Nous avons évoqué plus haut NewRelic.

Monitoring NewRelic

Pour une meilleure intégration, nous recommandons l’utilisation du bundle EkinoNewRelicBundle. Ce bundle va s’occuper d’envoyer le nom de la route symfony2 à NewRelic et il sera ainsi plus aisé d’exploiter les données présentes dans NewRelic. D’autres fonctionnalités sont présentes, notamment l’envoi de toutes les exceptions (qui n’implémentent pas HttpExceptionInterface).


ekino_new_relic:
    enabled:        true
    api_key:        %new_relic_api_key%
    license_key:    %new_relic_license_key%
    log_exceptions: true

Une commande est également disponible afin de pouvoir notifier NewRelic d’un déploiement. Cela vous permettra de détecter si des problèmes surviennent suite à un déploiement :


php app/console newrelic:notify-deployment

Cette fonctionnalité n’est malheureusement présente que pour les utilisateurs payants de Newrelic.

Conclusion

Nous vous avons présenté deux des outils que nous utilisons en priorité sur nos projets. D’autres solutions sont envisageables. Il est possible de compléter la stack avec des outils comme Grafana, InfluxDB, collectd. NewRelic dispose d’un mécanisme d’alerting assez efficace, ce n’est pas le cas, par défaut, pour ELK. Il est possible de lui associer Watcher ou ElastAlert que nous n’avons pas encore pris le temps d’essayer, mais dont nous vous parlerons certainement dans un prochain article.

Mettre une application web en production sans monitoring, c’est considérer qu’elle ne plante jamais, est toujours rapide, et est toujours accessible à vos utilisateurs : c’est vivre au pays des poneys arc-en-ciel à paillettes. Se contenter des fichiers de logs par défaut n’est pas suffisant, vous n’allez jamais les consulter, et vous ne verrez pas tout. Sortez couverts, mettez en place un vrai monitoring !

Nos formations sur le sujet

  • Symfony avancée

    Décou­vrez les fonc­tion­na­li­tés et concepts avan­cés de Symfo­ny

blog comments powered by Disqus