Logging in TypeScript-Anwendungen: Best Practices in der Praxis

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Logging in TypeScript-Anwendungen: Best Practices in der Praxis



Logging ist ein grundlegender Bestandteil jeder Production-Anwendung. Es ermöglicht nicht nur die Nachverfolgung der Codeausführung und das Auffinden von Fehlern, sondern auch die Durchführung von Sicherheitsaudits, die Analyse der Leistung und das Debuggen komplexer Szenarien. In TypeScript wird der Ansatz zum Logging mit seinem leistungsstarken Typsystem noch flexibler und zuverlässiger. In diesem Artikel werden wir die Best Practices des Loggings anhand konkreter Beispiele erläutern.



1. Auswahl der Bibliothek und Konfiguration des Loggers



Das Erste, womit man beginnen sollte, ist die Auswahl einer geeigneten Bibliothek. Zu den beliebten Lösungen gehören winston und pino. Beide unterstützen TypeScript von Haus aus, haben aber unterschiedliche Prioritäten: winston – Flexibilität und umfangreiche Funktionalität, pino – maximale Leistung.



Betrachten wir ein Beispiel für die Konfiguration von winston mit Typisierung:



import winston from 'winston';

const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service: 'user-service' }, transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ), }), new winston.transports.File({ filename: 'logs/error.log', level: 'error' }), new winston.transports.File({ filename: 'logs/combined.log' }), ],});

export default logger;


Für pino ist die Konfiguration prägnanter, aber nicht weniger effektiv:



import pino from 'pino';

const logger = pino({ level: process.env.LOG_LEVEL || 'info', transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard', }, },});

export default logger;


Tipp: Lagern Sie die Konfiguration des Log-Levels immer in Umgebungsvariablen aus (LOG_LEVEL). In der Produktion wird normalerweise info oder warn verwendet, in der Entwicklung debug.



2. Strukturiertes Logging und Kontext



Einer der Hauptfehler ist das Loggen einfacher Zeichenketten. Verwenden Sie stattdessen strukturierte Objekte. Diese ermöglichen ein einfaches Filtern und Aggregieren von Logs in Systemen wie ELK, Grafana oder Datadog.



Beispiel für schlechtes Logging:



logger.info('User logged in successfully');


Beispiel für gutes Logging mit Kontext:



logger.info({  message: 'User logged in',  userId: user.id,  email: user.email,  loginMethod: 'oauth',  ip: request.ip,  duration: Date.now() - startTime,});


Der Einfachheit halber können Sie einen typisierten Wrapper erstellen:



interface LogContext {  requestId?: string;  userId?: string;  action?: string;  [key: string]: unknown;}

function logWithContext(message: string, context: LogContext = {}): void { logger.info({ message, ...context });}

// VerwendunglogWithContext('Order processed', { orderId: '12345', userId: 'user_678', total: 99.99 });


Dieser Ansatz stellt sicher, dass jeder Logeintrag die für die Analyse wichtige Informationen enthält.



3. Logging von Fehlern und Ausnahmen



Die Fehlerbehandlung ist der wichtigste Teil des Loggings. Loggen Sie immer den vollständigen Stack-Trace des Fehlers und den Kontext, in dem er aufgetreten ist. Verwenden Sie nicht console.error – es bietet keine Flexibilität für Rotation und Formatierung.



Das richtige Pattern mit TypeScript:



import logger from './logger';

async function fetchUserData(userId: string): Promise<UserData> { try { const response = await api.get(`/users/${userId}`); ret

Blogs

Buchempfehlungen