Logging in JavaScript-Anwendungen: Best Practices für Node.js
Beim Logging geht es nicht nur darum, Nachrichten auf der Konsole auszugeben. In modernen Node.js-Anwendungen ist es ein kritisches Werkzeug zum Debuggen, Überwachen und Prüfen. Korrekt konfiguriertes Logging ermöglicht es Ihnen, Fehler schnell zu finden, das Benutzerverhalten zu analysieren und die Servicestabilität sicherzustellen. In diesem Artikel behandeln wir Best Practices für das Logging in JavaScript (Node.js), von der Auswahl einer Bibliothek bis zur Einrichtung der zentralisierten Protokollsammlung.
1. Auswahl einer Logging-Bibliothek
Das eingebaute console.log ist nur für die Entwicklung geeignet. Für Produktionsumgebungen werden spezialisierte Bibliotheken benötigt, die Logging-Ebenen, Formatierung, Dateirotation und Integration mit externen Systemen bieten.
Betrachten wir drei beliebte Optionen:
- Winston — die beliebteste Bibliothek. Flexibel, mit Unterstützung für mehrere Transports (Dateien, Konsole, HTTP, Datenbanken). Ideal für komplexe Systeme.
- Pino — ein ultraschneller Logger. Empfohlen für hochlastige Anwendungen, bei denen die Leistung entscheidend ist.
- Bunyan — erzeugt Logs im JSON-Format. Praktisch für die maschinelle Verarbeitung.
Winston-Setup-Beispiel:
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 gestartet');logger.error('Datenbankverbindungsfehler', { db: 'main' });2. Verwendung von Logging-Ebenen
Logging-Ebenen helfen dabei, Nachrichten nach Wichtigkeit zu filtern. Die Standard-Hierarchie (von der geringsten zur kritischsten):
- debug — detaillierte Debugging-Informationen (nur für die Entwicklung).
- info — Standardereignisse (Anfrage verarbeitet, Benutzer authentifiziert).
- warn — potenzielle Probleme (niedriger Speicher, langsame Anfrage).
- error — kritische Fehler (Modulabsturz, Ausnahme).
Regel: Verwenden Sie in der Produktion die Stufe info oder höher. debug sollte deaktiviert werden, um das Füllen der Datenträger und eine Leistungsminderung zu vermeiden.
Beispiel für dynamischen Ebenenwechsel:
const logger = require('./logger');
if (process.env.LOG_LEVEL) { logger.level = process.env.LOG_LEVEL;}
logger.debug('Diese Nachricht erscheint nicht in der Produktion');logger.info('Benutzer angemeldet');logger.error('Speichern der Daten fehlgeschlagen');3. Strukturierte Logs (JSON)
Textlogs sind schwer zu parsen. Die moderne Praxis besteht darin, strukturierte Logs im JSON-Format zu verwenden. Dies ermöglicht eine einfache Integration mit Analysesystemen (ELK, Splunk, Grafana Loki).
Was sollte in jedem Log enthalten sein:
- timestamp — genaue Ereigniszeit (ISO 8601).
- level — Logging-Ebene.
- message — menschenlesbare Beschreibung.
- context — zusätzliche Daten (Anfrage-ID, Benutzername, Fehlercode).
Beispiel mit Pino:
const pino = require('pino');
const logger = pino({ level: 'info', timestamp: pino.stdTimeFunctions.isoTime, formatters: { level(label) { return