Best Practices für Error Logging in JavaScript
  JavaScript-Anwendungen in der Produktivumgebung scheitern täglich still und leise. Benutzer stoßen auf Fehler, die Entwickler nie zu Gesicht bekommen, was zu schlechten Erfahrungen und Umsatzverlusten führt. Der Unterschied zwischen Anwendungen, die diese Probleme erfassen, und solchen, die es nicht tun? Ordnungsgemäßes Error Logging.
Dieser Artikel behandelt wesentliche Praktiken für die Implementierung robuster JavaScript-Fehlerprotokollierung in Frontend- und Backend-Umgebungen. Sie lernen, wie Sie über console.log hinausgehen, strukturiertes Logging mit bewährten Frameworks implementieren und ein System aufbauen, das kritische Fehler erfasst, bevor Benutzer sie melden.
Wichtigste Erkenntnisse
- Console Logging fehlt die Persistenz, Zentralisierung und Struktur, die für Produktivumgebungen erforderlich sind
 - Strukturiertes Logging mit Frameworks wie Winston oder Pino liefert maschinenlesbare Daten zur Analyse
 - Frontend-Fehlerbehandlung erfordert globale Handler und Framework-spezifische Lösungen wie React Error Boundaries
 - Der Schutz sensibler Daten und die Einbeziehung kontextbezogener Informationen sind entscheidend für effektives Logging
 
Warum Console Logging in der Produktion nicht ausreicht
Die meisten Entwickler beginnen mit console.log() zum Debuggen. Während dieser Ansatz während der Entwicklung ausreichend ist, versagt er in der Produktion:
// This error disappears into the user's browser
try {
  processPayment(order);
} catch (error) {
  console.error(error); // Lost forever in production
}
Console-Methoden fehlt:
- Persistenz über die aktuelle Sitzung hinaus
 - Zentralisierte Erfassung über alle Benutzer hinweg
 - Strukturierte Daten zur Analyse
 - Schweregrade zur Priorisierung
 - Schutz sensibler Daten
 
Produktionsanwendungen benötigen Logging, das Fehler erfasst, strukturiert und an einen zentralen Ort zur Analyse übermittelt.
Implementierung von strukturiertem Logging mit bewährten Frameworks
Auswahl des richtigen Frameworks
Für Node.js-Logging dominieren zwei Frameworks das Ökosystem:
Winston bietet Flexibilität und umfangreiche Transport-Optionen:
const winston = require('winston');
const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'error.log', level: 'error' })
  ]
});
Pino priorisiert Performance mit minimalem Overhead:
const pino = require('pino');
const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  timestamp: pino.stdTimeFunctions.isoTime,
  formatters: {
    level: (label) => ({ level: label })
  }
});
Strukturierung Ihrer Logs
Ersetzen Sie unstrukturierte Strings durch JSON-Objekte, die Maschinen parsen und analysieren können:
// Bad: Unstructured string
logger.info(`User ${userId} failed login attempt`);
// Good: Structured JSON
logger.info({
  event: 'login_failed',
  userId: userId,
  ip: request.ip,
  timestamp: new Date().toISOString(),
  userAgent: request.headers['user-agent']
});
Discover how at OpenReplay.com.
Wesentliche Komponenten effektiver JavaScript-Fehlerprotokollierung
1. Verwenden Sie geeignete Log-Level
Implementieren Sie konsistente Schweregrade in Ihrer gesamten Anwendung:
logger.debug('Detailed debugging information');
logger.info('Normal application flow');
logger.warn('Warning: degraded performance detected');
logger.error('Error occurred but application continues');
logger.fatal('Critical failure, application shutting down');
2. Schließen Sie immer Stack Traces ein
Erfassen Sie den vollständigen Fehlerkontext zum Debuggen:
process.on('uncaughtException', (error) => {
  logger.fatal({
    message: error.message,
    stack: error.stack,
    timestamp: new Date().toISOString()
  });
  process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
  logger.error({
    message: 'Unhandled Promise Rejection',
    reason: reason,
    promise: promise
  });
});
3. Fügen Sie kontextbezogene Informationen hinzu
Beziehen Sie Request-IDs, User-IDs und Sitzungsdaten ein, um Probleme nachzuverfolgen:
const requestLogger = logger.child({
  requestId: generateRequestId(),
  sessionId: request.session.id
});
requestLogger.info('Processing payment request');
4. Schützen Sie sensible Daten
Protokollieren Sie niemals Passwörter, Tokens oder persönliche Informationen:
const logger = pino({
  redact: ['password', 'creditCard', 'ssn', 'authorization']
});
// These fields will be automatically redacted
logger.info({
  user: email,
  password: 'secret123', // Will show as [REDACTED]
  action: 'login_attempt'
});
Frontend-Fehlerbehandlungsstrategien
Globale Error Handler
Erfassen Sie alle unbehandelten Fehler in Browser-Umgebungen:
window.addEventListener('error', (event) => {
  logToServer({
    message: event.message,
    source: event.filename,
    line: event.lineno,
    column: event.colno,
    stack: event.error?.stack
  });
});
window.addEventListener('unhandledrejection', (event) => {
  logToServer({
    type: 'unhandledRejection',
    reason: event.reason,
    promise: event.promise
  });
});
React Error Boundaries
Implementieren Sie für React-Anwendungen Error Boundaries, um Komponentenfehler abzufangen:
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  componentDidCatch(error, errorInfo) {
    logger.error({
      message: error.toString(),
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString()
    });
  }
  render() {
    if (this.state.hasError) {
      return <h2>Something went wrong. Please refresh the page.</h2>;
    }
    return this.props.children;
  }
}
Zentralisierung von Logs zur Analyse
Leiten Sie alle Logs an stdout weiter und lassen Sie Ihre Infrastruktur das Routing übernehmen:
// Configure logger to output to stdout only
const logger = pino({
  transport: {
    target: 'pino-pretty',
    options: {
      destination: 1 // stdout
    }
  }
});
Dieser Ansatz ermöglicht es Docker, Kubernetes oder Log-Shippern wie Fluentd, Logs zu sammeln und an zentralisierte Systeme zur Analyse weiterzuleiten. Implementieren Sie für clientseitige Anwendungen einen einfachen Endpunkt, um Logs von Browsern zu empfangen und an Ihre zentralisierte Logging-Infrastruktur weiterzuleiten.
Fazit
Effektives JavaScript-Error-Logging erfordert mehr als nur den Ersatz von console.log durch ein Framework. Es erfordert strukturierte Daten, geeignete Schweregrade, umfassenden Fehlerkontext und zentralisierte Erfassung. Durch die Implementierung dieser Praktiken mit Frameworks wie Winston oder Pino, den Schutz sensibler Daten und die Einrichtung geeigneter Error Boundaries im Frontend-Code schaffen Sie ein System, das Probleme erfasst, bevor sie Benutzer beeinträchtigen. Beginnen Sie mit diesen Grundlagen und erweitern Sie dann basierend auf den spezifischen Monitoring-Anforderungen Ihrer Anwendung.
Häufig gestellte Fragen
Pino hat minimalen Overhead und fügt in den meisten Fällen nur 2-3% Latenz hinzu. Winston ist etwas schwerer, aber für die meisten Anwendungen immer noch vernachlässigbar. Beide sind produktionsreif und werden von Anwendungen mit hohem Traffic weltweit eingesetzt.
Verwenden Sie integrierte Redaction-Funktionen in Ihrem Logging-Framework, um sensible Felder automatisch zu maskieren. Definieren Sie eine Liste von Feldnamen, die geschwärzt werden sollen, wie Passwörter, Tokens und Kreditkartennummern. Überprüfen Sie Ihre Logs regelmäßig auf versehentliche Datenoffenlegung.
Protokollieren Sie Fehler auf beiden Seiten. Clientseitiges Logging erfasst browserspezifische Probleme und JavaScript-Fehler, die Ihren Server nie erreichen. Serverseitiges Logging behandelt API-Fehler und Backend-Ausfälle. Verwenden Sie ein zentralisiertes System, um beide Quellen zu aggregieren.
Konfigurieren Sie Alerts für Error- und Fatal-Level sofort. Warning-Level können tägliche Zusammenfassungen auslösen. Info- und Debug-Level sollten durchsuchbar sein, aber keine Alerts auslösen, es sei denn, Sie untersuchen spezifische Probleme oder überwachen kritische Geschäftsereignisse.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.