Back

Mejores Prácticas para el Registro de Errores en JavaScript

Mejores Prácticas para el Registro de Errores en JavaScript

Las aplicaciones JavaScript en producción fallan silenciosamente todos los días. Los usuarios encuentran errores que los desarrolladores nunca ven, lo que genera experiencias deficientes y pérdida de ingresos. ¿La diferencia entre las aplicaciones que detectan estos problemas y las que no? Un registro de errores adecuado.

Este artículo cubre prácticas esenciales para implementar un registro robusto de errores en JavaScript en entornos frontend y backend. Aprenderás cómo ir más allá de console.log, implementar registro estructurado con frameworks probados y construir un sistema que capture errores críticos antes de que los usuarios los reporten.

Puntos Clave

  • El registro por consola carece de persistencia, centralización y estructura necesarias para entornos de producción
  • El registro estructurado con frameworks como Winston o Pino proporciona datos analizables por máquinas
  • El manejo de errores en frontend requiere manejadores globales y soluciones específicas de frameworks como React Error Boundaries
  • Proteger datos sensibles e incluir información contextual son críticos para un registro efectivo

Por Qué el Registro por Consola es Insuficiente en Producción

La mayoría de los desarrolladores comienzan con console.log() para depuración. Aunque es adecuado durante el desarrollo, este enfoque falla en producción:

// This error disappears into the user's browser
try {
  processPayment(order);
} catch (error) {
  console.error(error); // Lost forever in production
}

Los métodos de consola carecen de:

  • Persistencia más allá de la sesión actual
  • Recopilación centralizada entre usuarios
  • Datos estructurados para análisis
  • Niveles de severidad para priorización
  • Protección de datos sensibles

Las aplicaciones en producción necesitan un registro que capture, estructure y transmita errores a una ubicación central para su análisis.

Implementación de Registro Estructurado con Frameworks Probados

Elegir el Framework Adecuado

Para el registro en Node.js, dos frameworks dominan el ecosistema:

Winston ofrece flexibilidad y amplias opciones de transporte:

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 prioriza el rendimiento con sobrecarga mínima:

const pino = require('pino');

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  timestamp: pino.stdTimeFunctions.isoTime,
  formatters: {
    level: (label) => ({ level: label })
  }
});

Estructurar tus Registros

Reemplaza cadenas no estructuradas con objetos JSON que las máquinas puedan analizar:

// 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']
});

Componentes Esenciales del Registro Efectivo de Errores en JavaScript

1. Usar Niveles de Registro Apropiados

Implementa niveles de severidad consistentes en toda tu aplicación:

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. Incluir Siempre Stack Traces

Captura el contexto completo del error para depuración:

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. Agregar Información Contextual

Incluye IDs de solicitud, IDs de usuario y datos de sesión para rastrear problemas:

const requestLogger = logger.child({
  requestId: generateRequestId(),
  sessionId: request.session.id
});

requestLogger.info('Processing payment request');

4. Proteger Datos Sensibles

Nunca registres contraseñas, tokens o información personal:

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'
});

Estrategias de Manejo de Errores en Frontend

Manejadores Globales de Errores

Captura todos los errores no manejados en entornos de navegador:

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

Para aplicaciones React, implementa error boundaries para capturar errores de componentes:

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;
  }
}

Centralizar Registros para Análisis

Dirige todos los registros a stdout y deja que tu infraestructura maneje el enrutamiento:

// Configure logger to output to stdout only
const logger = pino({
  transport: {
    target: 'pino-pretty',
    options: {
      destination: 1 // stdout
    }
  }
});

Este enfoque permite que Docker, Kubernetes o transportadores de logs como Fluentd recopilen y enruten registros a sistemas centralizados para análisis. Para aplicaciones del lado del cliente, implementa un endpoint simple para recibir y reenviar registros desde navegadores a tu infraestructura de registro centralizada.

Conclusión

El registro efectivo de errores en JavaScript requiere más que reemplazar console.log con un framework. Demanda datos estructurados, niveles de severidad apropiados, contexto completo de errores y recopilación centralizada. Al implementar estas prácticas con frameworks como Winston o Pino, proteger datos sensibles y establecer error boundaries adecuados en el código frontend, creas un sistema que detecta problemas antes de que impacten a los usuarios. Comienza con estos fundamentos y luego expande según las necesidades específicas de monitoreo de tu aplicación.

Preguntas Frecuentes

Pino tiene una sobrecarga mínima, agregando solo 2-3% de latencia en la mayoría de los casos. Winston es ligeramente más pesado pero aún insignificante para la mayoría de las aplicaciones. Ambos están listos para producción y son utilizados por aplicaciones de alto tráfico en todo el mundo.

Utiliza las funciones de redacción integradas en tu framework de registro para enmascarar automáticamente campos sensibles. Define una lista de nombres de campos a redactar como contraseñas, tokens y números de tarjetas de crédito. Siempre audita tus registros regularmente para detectar exposición accidental de datos.

Registra errores en ambos lados. El registro del lado del cliente captura problemas específicos del navegador y errores de JavaScript que nunca llegan a tu servidor. El registro del lado del servidor maneja errores de API y fallos del backend. Usa un sistema centralizado para agregar ambas fuentes.

Configura alertas para los niveles error y fatal inmediatamente. Los niveles de advertencia pueden activar resúmenes diarios. Los niveles info y debug deben ser buscables pero no activar alertas a menos que estés investigando problemas específicos o monitoreando eventos críticos del negocio.

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.

OpenReplay