Journalisation dans les applications JavaScript : bonnes pratiques pour Node.js
La journalisation ne consiste pas seulement à écrire des messages dans la console. Dans les applications Node.js modernes, c'est un outil essentiel pour le débogage, la surveillance et l'audit. Une journalisation correctement configurée permet de trouver rapidement les erreurs, d'analyser le comportement des utilisateurs et d'assurer la stabilité du service. Dans cet article, nous allons examiner les bonnes pratiques de journalisation en JavaScript (Node.js), du choix de la bibliothèque à la configuration de la collecte centralisée des logs.
1. Choix de la bibliothèque de journalisation
Le console.log intégré est uniquement adapté au développement. Pour un environnement de production, des bibliothèques spécialisées sont nécessaires, offrant des niveaux de journalisation, du formatage, une rotation des fichiers et une intégration avec des systèmes externes.
Examinons trois options populaires :
- Winston — la bibliothèque la plus populaire. Flexible, avec le support de multiples transports (fichiers, console, HTTP, bases de données). Idéale pour les systèmes complexes.
- Pino — un logger ultra-rapide. Recommandé pour les applications à forte charge où la performance est critique.
- Bunyan — génère des logs au format JSON. Pratique pour le traitement automatisé.
Exemple de configuration avec Winston :
const winston = require('winston');
const logger = winston.createLogger({ level: 'info', format: winston.format.json(), defaultMeta: { service: 'user-service' }, transports: [ new winston.transports.File({ filename: 'error.log', level: 'error' }), new winston.transports.File({ filename: 'combined.log' }), ],});
if (process.env.NODE_ENV !== 'production') { logger.add(new winston.transports.Console({ format: winston.format.simple(), }));}
logger.info('Service démarré');logger.error('Erreur de connexion à la base de données', { db: 'main' });2. Utilisation des niveaux de journalisation
Les niveaux de journalisation aident à filtrer les messages par importance. La hiérarchie standard (du moins au plus critique) :
- debug — informations de débogage détaillées (développement uniquement).
- info — événements standards (requête traitée, utilisateur authentifié).
- warn — problèmes potentiels (faible niveau de mémoire, requête lente).
- error — erreurs critiques (panne de module, exception).
Règle : En production, utilisez le niveau info ou supérieur. debug doit être désactivé pour ne pas saturer les disques et ne pas réduire les performances.
Exemple de changement dynamique de niveau :
const logger = require('./logger');
if (process.env.LOG_LEVEL) { logger.level = process.env.LOG_LEVEL;}
logger.debug('Ce message n\'apparaîtra pas en production');logger.info('Utilisateur connecté');logger.error('Impossible de sauvegarder les données');3. Logs structurés (JSON)
Les logs textuels sont difficiles à analyser. La pratique moderne consiste à utiliser des logs structurés au format JSON. Cela permet une intégration facile avec les systèmes d'analyse (ELK, Splunk, Grafana Loki).
Ce que chaque log doit contenir :
- timestamp — heure exacte de l'événement (ISO 8601).
- level — niveau de journalisation.
- message — description lisible par un humain.
- context — données supplémentaires (ID de requête, nom d'utilisateur, code d'erreur).
Exemple avec Pino :
const pino = require('pino');
const logger = pino({ level: 'info', timestamp: pino.stdTimeFunctions.isoTime, formatters: { level(label) { return