Volver a explorar Snippets

Performance Interceptor: Middleware de Monitoreo de Latencia para Express

JAVASCRIPT 14 de mayo de 2026 36 lecturas
Un middleware avanzado para Node.js/Express que calcula el tiempo de respuesta exacto de cada petición. Utiliza 'process.hrtime' para precisión de nanosegundos y formatea la salida con códigos de colores ANSI para una terminal profesional.

El Arte de Medir la Latencia en Node.js

En el desarrollo de APIs RESTful escalables, el monitoreo del rendimiento no es un lujo, es una necesidad absoluta. Cuando tu backend empieza a recibir miles de peticiones, identificar los cuellos de botella se vuelve crítico. Muchos desarrolladores junior recurren a métodos básicos como Date.now() o console.time() para medir cuánto tarda una ruta en responder. Sin embargo, estas herramientas son insuficientes y carecen de la precisión necesaria para un análisis de rendimiento profesional.

En este snippet, he diseñado un Performance Interceptor Middleware para Express que resuelve este problema utilizando herramientas nativas de Node.js de alta precisión.

¿Por qué utilizar process.hrtime()?

El reloj del sistema operativo estándar está sujeto a fluctuaciones (como la sincronización NTP), lo que hace que Date.now() sea impreciso para mediciones a nivel de milisegundos. Para evitar esto, nuestro interceptor utiliza process.hrtime(). Este método invoca el reloj de alta resolución del sistema (High-Resolution Time), el cual es independiente del reloj del sistema y nos otorga una precisión de nanosegundos.

Anatomía del Middleware: ¿Cómo funciona?

La arquitectura de este interceptor se basa en la naturaleza asíncrona de Node.js y el ciclo de vida de las peticiones HTTP en Express:

  1. Captura Inicial: Tan pronto como la petición entra al servidor, el middleware captura el timestamp exacto mediante process.hrtime() antes de ceder el control al siguiente controlador con next().
  2. El Evento res.on('finish'): Aquí radica el "secreto" de este código. No podemos simplemente medir el tiempo después del next(), ya que la ejecución es asíncrona y la respuesta aún no se ha enviado al cliente. Al suscribirnos al evento finish del objeto de respuesta (res), garantizamos que el cronómetro se detenga exactamente cuando el último byte de datos ha salido de nuestro servidor.
  3. Cálculo Matemático: El resultado de process.hrtime(start) es un array (tupla) que contiene [segundos, nanosegundos]. El código realiza una conversión matemática rápida combinando ambos valores para entregar un resultado unificado en milisegundos con tres decimales de precisión.
  4. Experiencia de Desarrollador (DX): Un buen log debe ser legible. He implementado Códigos de Escape ANSI para colorear la salida en la consola. Si la petición es exitosa (Status 200-399), el código de estado brillará en verde. Si ocurre un error (Status 400+), se pintará de rojo, permitiendo a los ingenieros de DevOps y Backend detectar fallos de un solo vistazo en la terminal.

Implementación en tu Arquitectura

Este fragmento de código es agnóstico, lo que significa que puedes inyectarlo al principio de tu archivo server.js o app.js en cualquier proyecto de Express. Al ser un middleware global, rastreará absolutamente todas las rutas sin necesidad de ensuciar la lógica de negocio de tus controladores individuales.

Te invito a ejecutar el código en la Terminal Interactiva de arriba para que veas en tiempo real cómo el simulador retrasa la petición deliberadamente y el interceptor captura la latencia exacta con su respectivo formato de colores.

/**
 * 🚀 Performance Interceptor Middleware
 * Monitorea el tiempo de respuesta de tu API con alta precisión.
 */

const express = require('express');
const app = express();

const performanceMonitor = (req, res, next) => {
    // Capturamos el tiempo de inicio con alta resolución
    const start = process.hrtime();

    // Evento que se dispara cuando la respuesta se ha enviado al cliente
    res.on('finish', () => {
        // Calculamos la diferencia
        const diff = process.hrtime(start);
        
        // Convertimos a milisegundos (segundos * 1e3 + nanosegundos / 1e6)
        const timeInMs = (diff[0] * 1e3 + diff[1] * 1e-6).toFixed(3);

        // Definimos colores según el estado (ANSI Codes)
        const statusColor = res.statusCode >= 400 ? '\x1b[31m' : '\x1b[32m'; // Rojo o Verde
        const reset = '\x1b[0m';
        const cyan = '\x1b[36m';

        console.log(
            `[${cyan}LOG${reset}] ${req.method} ${req.url} - ` +
            `${statusColor}${res.statusCode}${reset} - ` +
            `⏱️  ${timeInMs}ms`
        );
    });

    next();
};

// --- SIMULACIÓN PARA EL PLAYGROUND ---

app.use(performanceMonitor);

app.get('/api/test', (req, res) => {
    // Simulamos una carga de trabajo de 150ms
    setTimeout(() => {
        res.status(200).json({ message: "Data procesada correctamente" });
    }, 150);
});

console.log('--- ⚡ MONITOR DE RENDIMIENTO ACTIVADO ---');
console.log('Ejecutando petición de prueba a /api/test...\n');

// Mock para disparar la ejecución en tu terminal
const mockReq = { method: 'GET', url: '/api/test' };
const mockRes = { 
    statusCode: 200, 
    on: (event, cb) => setTimeout(cb, 155) // Simulamos el evento 'finish'
};

// Disparamos el log
performanceMonitor(mockReq, mockRes, () => {});
¿Qué te pareció?
🔥 Brillante 1
💡 Me sirvió 0
🚀 A otro nivel 0