Introduction : Pourquoi journaliser en TypeScript ?
La journalisation ne se résume pas à écrire des messages dans la console. Dans les applications TypeScript modernes (côté serveur avec Node.js, côté client avec React/Angular ou projets full-stack), la journalisation devient un outil critique pour le débogage, la surveillance et l'analyse des performances. Sans une journalisation de qualité, les développeurs passent des heures à reproduire les erreurs, et les ingénieurs DevOps ne peuvent pas identifier rapidement la cause d'un incident en production.
TypeScript, en tant que surcouche de JavaScript, ajoute un typage strict, ce qui permet de créer des systèmes de journalisation plus fiables et prévisibles. Dans cet article, nous allons examiner les meilleures pratiques pour vous aider à organiser une journalisation efficace dans vos projets TypeScript.
Principes fondamentaux de la journalisation
Niveaux de journalisation
L'utilisation correcte des niveaux de journalisation est la base de tout système de surveillance. En TypeScript, il est d'usage d'utiliser les niveaux suivants (par ordre croissant d'importance) :
debug— informations de débogage détaillées (développement uniquement) ;info— messages d'information standards (démarrage du serveur, requêtes) ;warn— avertissements (problèmes non critiques) ;error— erreurs nécessitant une attention ;fatal— erreurs critiques entraînant l'arrêt de l'application.
Exemple de configuration des niveaux avec la bibliothèque Winston :
import winston from 'winston';
const logger = winston.createLogger({ level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', format: winston.format.json(), transports: [ new winston.transports.Console(), new winston.transports.File({ filename: 'error.log', level: 'error' }), ],});
logger.info('Serveur démarré sur le port 3000');logger.warn('Mémoire proche de la limite');logger.error('Erreur de connexion à la base de données');Journaux structurés
Évitez les simples messages textuels. Utilisez des journaux structurés avec des informations contextuelles (format JSON). Cela simplifie la recherche et l'analyse dans des systèmes comme ELK ou Grafana.
// Mauvaislogger.info(`Utilisateur ${userId} a effectué l'action ${action}`);
// Bonlogger.info('Action utilisateur', { userId: userId, action: action, timestamp: new Date().toISOString(), ip: request.ip,});Cette approche permet de filtrer les journaux par champs et de construire des graphiques.
Meilleures pratiques pour TypeScript
Utilisation de TypeScript pour typer les journaux
TypeScript permet de définir des interfaces pour le contexte des journaux, ce qui évite les erreurs accidentelles dans les noms de champs :
interface LogContext { userId: string; action: string; durationMs: number; success: boolean;}
function logUserAction(context: LogContext): void { logger.info('User action', context);}
// Le compilateur vérifiera que tous les champs sont transmis correctementlogUserAction({ userId: '123', action: 'login', durationMs: 150, success: true,});Évitez de journaliser les données sensibles
Ne journalisez jamais les mots de passe, jetons, numéros de carte de crédit ou données personnelles (RGPD). Utilisez des utilitaires de masquage :
function sanitizeLogData(data: Record<string, unknown>): Record<string, unknown> { const sensitiveFields = ['password', 'token', 'ssn']; const sanitized = { ...data }; for (const field of sensitiveFields) { if (sanitized[field]) { sanitized[field] = '***'; } } return sanitized;}
logger.info('Inscription utilisateur', sanitizeLogData(userData));Journalisation asynchrone et performance
Dans les applications à forte charge, la journalisation synchrone peut ralentir le travail. Utilisez des transports asynchrones (par exemple, winston prend en charge la mise en mémoire tampon).