Retour à l'accueil

Logger : conception pour les diagnostics en production

L'article couvre les aspects clés de la conception de logger pour la production : liaison aux tâches via canaux, déduplication, sous-systèmes et contrôle dynamique. Exemples de code pour logme et comparaison avec spdlog, Quill. Focus sur les diagnostics sans perte de performance.

Conception efficace de logger pour les systèmes à forte charge
Advertisement 728x90

Conception de logger : diagnostics et contrôle en production prioritaires

Dans les systèmes de production, les loggers ne sont pas évalués sur la vitesse de leur API, mais sur leur capacité à aider à diagnostiquer rapidement les incidents sans alourdir la charge. L'enregistrement de logs introduit un surcoût, minimisé en fonctionnement normal. Mais en cas de problème, des détails insuffisants ou des logs chaotiques rendent le dépannage impossible. Un bon logger garantit la diagnostiquabilité sans sacrifier les performances.

Le problème surgit quand la structure des logs reflète le code au lieu des processus métier. Dans les systèmes multithreadés, les messages de tâches différentes s'entremêlent, rendant difficile le suivi d'une requête spécifique.

Associer le contexte aux tâches

La solution consiste à associer les logs aux tâches, pas aux sites d'appel. Passer le contexte par paramètres alourdit les signatures de fonctions. Mieux vaut l'attacher au thread d'exécution.

Google AdInline article slot

Dans logme, cela se fait via des canaux de thread :

auto requestCh = Logme::Instance->CreateChannel(Logme::ID("req-42"));
LogmeThreadChannel(requestCh);
HandleRequest();

Le code interne logue automatiquement vers le canal :

void ParseHeaders() {
    LogmeW("invalid header");
}

Les logs s'organisent désormais par opération. Dans spdlog et Quill, le contexte tourne autour du logger, plus simple mais moins adapté aux tâches.

Google AdInline article slot

Un autre souci est le bruit des messages répétés. Les erreurs de retry inondent les logs de doublons. Des limites au niveau événement résolvent cela :

LogmeW(LOGME_ONCE4THIS, "disque plein");

Le message n'apparaît qu'une fois par instance de classe, gardant les logs lisibles.

Routage flexible des messages

Une config globale ne suffit pas. Avec HTTP/2, il faut séparer logs de connexion et de requête. Un canal de requête se lie au canal protocole, mais les détails de requête ne doivent pas polluer le log principal.

Google AdInline article slot
Logme::Override ovr;
ovr.Add.DisableLink = true;
LogmeI(ovr, "détail spécifique à la requête");

Cela isole le message au canal local. Les événements généraux s'affichent partout ; les privés restent locaux.

Sous-systèmes pour un détail précis

Une dimension (canal) ne suffit pas. Les tâches ont des sous-systèmes : cache, réseau, parsing. Loguer sélectivement :

LOGME_SUBSYSTEM(cacheSid, "cache");
LOGME_SUBSYSTEM(parserSid, "parser");

LogmeD(cacheSid, "cache miss");
LogmeD(parserSid, "header analysé");

À l'exécution, activer seulement le sous-système nécessaire, comme le cache. Les autres restent muets, gardant les logs compacts.

Intégration avec les bibliothèques

Les bibliothèques tierces ont leur propre logging. On les intercepte et intègre :

void FfmpegLogCallback(void* ptr, int level, const char* fmt, va_list args) {
    char buffer[2048];
    vsnprintf(buffer, sizeof(buffer), fmt, args);

    Logme::Override ovr;
    ovr.Add.DisableLink = true;

    LogmeW(ovr, "[ffmpeg] %s", buffer);
}

Les messages suivent les mêmes règles : canaux, sous-systèmes, déduplication.

Le support de formats facilite la migration :

LogmeI("value=%i", value);
fLogmeI("value={}", value);
LogmeI() << "value=" << value;

logme fusionne styles fmt et stream, contrairement à spdlog (fmt seul) et Quill (fmt asynchrone).

Contrôle en production sans redémarrage

Dans les systèmes toujours actifs, les logs restent minimaux en temps normal. Lors d'incidents :

  • Soupçon sur le cache ? Activer son sous-système.
  • Isoler la tâche via canal.
  • Limiter les répétitions.

Le contrôle est dynamique via logmectl : niveaux, sous-systèmes, sans redémarrage.

Après correction, réduire les détails. Sinon, augmenter les logs globaux provoque une surcharge.

spdlog met l'accent sur la vitesse, Quill sur l'asynchronicité, logme sur le contrôle du flux de messages tout en préservant les performances.

Points clés :

  • Les loggers doivent grouper par tâches via canaux, pas loggers.
  • La déduplication au niveau événement réduit le bruit.
  • Les sous-systèmes permettent un détail ciblé à l'exécution.
  • L'intégration bibliothèques standardise la sortie.
  • Le contrôle dynamique sans redémarrage est essentiel en production.

— Editorial Team

Advertisement 728x90

Lire ensuite