Skip to the content.

Motivation

Ce document dĂ©finit la structure en sortie des logs, l’API pour les dĂ©veloppeurs et la façon de rassembler les diffĂ©rents Ă©lĂ©ments des logs (nom des paramĂštres, sĂ©vĂ©ritĂ©, texte du syslog et sa description pour le manuel).

Ce document ne traite pas de l’amĂ©lioration du contenu de chacun des logs (paramĂštres, texte, description, niveau de log).

  1. Facile pour les dĂ©veloppeurs : Écriture des logs, Maintenance du framework.
  2. Facile pour le manuel de l’utilisateur : Maintenance de la liste des logs et de leur description (avec internationalisation).
  3. Facile pour l’IT du client => Les logs sont structurĂ©s et nativement comprĂ©hensibles par les outils d’analyse de logs.

Analyse automatique des logs

Les Ă©quipes IT de supervision des applications utilisent des outils d’aide au traitement des logs issus de leur parc applicatif. Afin de rĂ©duire la charge de travail, les logs doivent ĂȘtre le plus compatible possible avec ces outils.

Ces outils sont compatibles avec le format Syslog dont la derniÚre norme est la RFC 5424 (la RFC 3164 était une recommandation préliminaire).

Ces outils sont aussi compatibles avec le format JSON. Mais ce document ne traite pas de la possibilité JSON.

Quelques exemples d’outils d’analyse de logs :

Splunk Enterprise

https://www.splunk.com

Logstash

https://www.elastic.co/fr/products

TrÚs utilisée avec avec ElasticSearch et Kibana.

GrayLog

https://www.graylog.org

DataLog

https://www.datadoghq.com

Finalité des logs

Les logs sont utilisĂ©s pour des besoins trĂšs variĂ©s. Voici quelques exemples d’activitĂ©s :

La liste finale des activitĂ©s sera Ă  Ă©tablir en faisant une passe sur les logs existants. (la liste sera certainement rĂ©duite Ă  un plus petit nombre d’activitĂ©s) Afin d’obtenir une liste d’activitĂ©s pertinentes, les pratiques les plus courantes pourraient ĂȘtre analysĂ©es.

Format syslog

<123>1 DateTimeTZ Hostname AppName ProcID MsgID [idA@1234 name="value"] [idB@1234 a="1" b="2"] BOMmessageUTF8
 ---  \  \                                      -----------------------
  |    \  2017-08-24T17:14:15.000003-07:00        |
  |     \                                         |
Priority SyslogVersion                          Structure Data

Priority

<123>

Version

<123>1
     ^

Toujours 1

DateTimeTZ

Horodatage

Hostname

FQDN, Hostname, IP


TODO: VĂ©rifier les pratiques courantes utilisĂ©es par d’autres applications similaires Pour des logs transmis par des clients Ă  un serveur, ce dernier pout indiquer l’identifiant unique du client.

AppName

TODO: VĂ©rifier les recommandation de la RFC 5424 et les conventions les plus courantes afin de ne pas suprendre les Ă©quipes IT de surveillance des logs.

ProcID

Process ID

MsgID

Identifiant unique pour un type de message de log

TODO: DĂ©finir comment obtenir cet identifiant unique

Structure Data

[sdId@1234 name1="value1" name2="value2" name3="value3"]

Si plusieurs SD utilisent un paramĂštre ayant la mĂȘme signification, le name doit ĂȘtre le mĂȘme.

Un mĂȘme SD peut contenir plusieurs paramĂštres ayant le mĂȘme name. Exemple pour indiquer deux adresses IP :

[sdId@1234 ip="10.22.22.22" ip="10.33.33.33"]

En absence de SD, mettre le signe tiret “-”.

Si plusieurs SD, un mĂȘme sdId@1234 ne doit pas ĂȘtre prĂ©sent plus de une fois.

Ces structures de donnĂ©es sont Ă  destination des outils d’analyse automatique de log. Donc, leur changement doit ĂȘtre bien pensĂ© pour Ă©viter toute rĂ©gression. Par consĂ©quent, chaque nouvelle structure doit bien ĂȘtre rĂ©flĂ©chie pour assurer sa pĂ©rennitĂ©.

BOMmessageUTF8

Optionnel, c’est une chaĂźne de caractĂšres en UTF-8 commençant par un BOM. Cette chaĂźne de caractĂšres est Ă  destination des humains, et peut changer entre deux versions. Les paramĂštres variables doivent se trouver dans la partie SD (structure de donnĂ©es). NĂ©anmoins cette chaĂźne peut Ă©galement rĂ©pĂ©ter quelques paramĂštres si cela amĂ©liore la comprĂ©hension du message Ă  destination des humains.

Exemples valides

<134>1 2017-10-11T22:14:15.003Z myapp.company.com MyModule1 1234 M42 - BOMCeci est un message de niveau information et sans structure de données
<134>1 2017-10-11T22:14:15.003Z myapp.company.com MyModule1 1235 M43 [metric@1234 sd="2"] BOMCeci est un métrique
<134>1 2017-10-11T22:14:15.003Z myapp.company.com MyModule2 1235 M43 [metric@1234 sd="2"] [debug@1234 file="a.c" line="111"]

Structuration des informations des logs

Les informations nécessaires à produire une ligne de log proviennent de différents objets.

Cette section propose d’éviter la redondance de ces informations et structure ces informations en les regroupant par affinitĂ© :

Schéma qui présente la répartition des informations nécessaires à la construction du log

Quelques exemples de Structured Data

id@1234 Structure générique pour tous les logs

[id@1234 activity="event" threadId="12345" threadName="main" moduleName="MyModule" transactionId="123"]

Le threadName est le nom du thread (fil d’exĂ©cution). Le nom du thread est bien souvent complĂ©mentaire (et plus explicite) que son threadId.

Les systĂšmes Windows et GNU permettent de nommer les threads.

Pour la glibc (pthread), cette fonctionnalité est arrivée avec la version 2.12 sortie en 2010 :

#include <pthread.h>
int pthread_setname_np (pthread_t thread, const char *name);
int pthread_getname_np (pthread_t thread, char *name, size_t len);

debug@1234 Uniquement en mode debug

[debug@1234 file="a.c" line="111" function="foo()"]

Consignes d’implĂ©mentation

Ne pas compliquer inutilement le code

Compatibilités

Interface intuitive

Manuel de l’utilisateur

Compatibilité des bibliothÚques de Log avec Syslog

Syslog(3) POSIX

#include <syslog.h>

void openlog(const char *ident, int option, int facility);
int setlogmask(int maskpri); // active/désactive les différents niveaux de log
void syslog  (int priority, const char *format, ...);
void vsyslog (int priority, const char *format, va_list ap); // identical but using 
void closelog(void);

const char* ident = "the AppName"; //
int option = LOG_PID;  // include PID with each message
int  facility = LOG_USER;
int level = LOG_DEBUG; // LOG_INFO LOG_NOTICE LOG_WARNING LOG_ERR LOG_CRIT LOG_ALERT LOG_EMERG
int priority = LOG_MAKEPRI(facility, level);
int maskpri = LOG_MASK(LOG_ERR) | LOG_MASK(LOG_CRIT) | LOG_MASK(LOG_ALERT) | LOG_MASK(LOG_EMERG);
maskpri = LOG_UPTO(LOG_ERR); // revient au mĂȘme

Inconvénients

Implémentations pour Windows

http://syslog-win32.sourceforge.net

Dernier changement en 2005 pour le code du client, et en 2014 pour le code du du démon qui dépend des bibliothÚques Glib, libiconv and libintl.

Forks avec des améliorations :

Spdlog

Very fast, header only, C++ logging library.

http://github.com/gabime/spdlog

spdlog permet de wrapper les appels vers l’API Syslog POSIX.

#define SPDLOG_ENABLE_SYSLOG
#include "spdlog/spdlog.h"

int main(int, char*[])
{
  std::string name   = "le nom du logger";
  std::string ident  = "l'AppName";
  int         option = LOG_PID;
  auto logger = spdlog::syslog_logger(name, ident, option);

  logger->warn("This is warning that will end up in syslog.");
}

Google glog

http://github.com/google/glog

Les macros SYSLOG, SYSLOG_IF et SYSLOG_EVERY_N utilisent l’API Syslog POSIX doit voici le wrapping :

void LogMessage::SendToSyslogAndLog() {
#ifdef HAVE_SYSLOG_H
  // Before any calls to syslog(), make a single call to openlog()
  static bool openlog_already_called = false;
  if (!openlog_already_called) {
    openlog(glog_internal_namespace_::ProgramInvocationShortName(),
            LOG_CONS | LOG_NDELAY | LOG_PID,
            LOG_USER);
    openlog_already_called = true;
  }

  // This array maps Google severity levels to syslog levels
  const int SEVERITY_TO_LEVEL[] = { LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG };
  syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)], "%.*s",
         int(data_->num_chars_to_syslog_),
         data_->message_text_ + data_->num_prefix_chars_);
  SendToLog();
#else
  LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
#endif
}

La remarque dans la documentation de glog s’applique Ă©galement Ă  toutes les autres utilisation des implĂ©mentations standards de Syslog POSIX :

These log to syslog as well as to the normal logs. If you use these at all, you need to be aware that syslog can drastically reduce performance, especially if it is configured for remote logging! Don’t use these unless you fully understand this and have a concrete need to use them. Even then, try to minimize your use of them.

Boost::log

http://www.boost.org/libs/log/doc/html/boost/log/sinks/syslog_backend.html

ImplĂ©mente une alternative Ă  l’implĂ©mentation Syslog POSIX standard.

Mais n’est pas conforme à la RFC 5424 et ne semble pas utiliser TCP (seulement UDP).

Par contre, la documentation conseille d’utiliser plutĂŽt l’implĂ©mentation Syslog POSIX standard afin de ne pas contourner les Ă©ventuels dispositifs de sĂ©curitĂ© :

On systems with native syslog implementation it may be preferable to utilize the POSIX syslog API instead of direct socket management in order to bypass possible security limitations that may be in action. To do so one has to pass the use_impl = native to the backend constructor. [
] Using use_impl = native on platforms with no native support for POSIX syslog API will have no effect.

G3log

Projet trĂšs actif, haute performance comme Spdlog.

TODO

Log4cpp

Log for C++

http://log4cpp.sourceforge.net/

Son interface (API) est trĂšs similaire Ă  celle de Log4j. Log4cpp est un vieux projet, en phase de maintenance corrective, avec du vieux C++98, compatible avec de trĂšs nombreuse versions de compilateurs, mais pas trĂšs sexy, ni performant.

Log4cpp propose un backend Syslog qui utilise l’implĂ©mentation POSIX standard :

SyslogAppender sends LoggingEvents to the local syslog system.

Autres


Autres bibliothĂšques C++ de logging : https://cpp.libhunt.com/categories/779-logging

Aspects qui restent à définir