npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mercy-logger

v2.1.4

Published

A fast, flexible and feature-rich logger for Node.js with worker threads support

Readme

Mercy Logger

Un logger rápido, flexible y con muchas características para Node.js con soporte para worker threads, rotación de archivos, transporte HTTP y más.

Características

  • 🚀 Alto rendimiento con soporte opcional para worker threads
  • 📁 Rotación de archivos por tamaño o fecha (on-demand, sin timers)
  • 🌐 Transporte HTTP con batch, reintentos y autenticación
  • 🎨 Múltiples formatos (texto y JSON)
  • 🔧 Altamente configurable
  • 🔇 Modo silencioso para desactivar completamente el logger
  • 📦 Dependencias mínimas usando solo APIs nativas de Node.js
  • 💾 Compresión automática de archivos rotados
  • 🔄 Recuperación automática de workers caídos
  • 🎯 Filtrado por nivel en cada transport
  • 🌍 Multiplataforma (Windows, Linux, macOS)

Instalación

npm install mercy-logger

Uso Básico

import Mercy from 'mercy-logger';

const logger = new Mercy({
  level: 'info',
  transports: [
    { type: 'console', format: 'text', colors: true },
    { type: 'file', filePath: './logs/app.log', format: 'json' }
  ]
});

logger.info('Application started');
logger.error('An error occurred', { userId: 123, action: 'login' });

Arquitectura

Componentes Principales

  1. Mercy (src/mercy.ts) - Clase principal del logger
  2. Worker Logger (src/workers/logger.worker.ts) - Worker thread para procesamiento asíncrono
  3. Transports (src/transports/index.ts) - Manejadores de destinos de logs
  4. Utils (src/utils/index.ts) - Utilidades para formateo, rotación, etc.
  5. Interfaces (src/interfaces/logger.interface.ts) - Definiciones de tipos

Modos de Operación

1. Modo Worker (por defecto)

  • Los logs se envían a un Worker Thread separado
  • El worker procesa y escribe los logs sin bloquear el hilo principal
  • Health checks cada 60 segundos (ping/pong)
  • Reconexión automática (hasta 3 intentos)
  • Si falla, hace fallback a modo directo

2. Modo Directo

  • Los logs se procesan en el mismo hilo
  • Se activa si useWorker: false o si el worker falla

Configuración

Configuración Principal

interface MercyConfig {
  level?: LogLevel;           // Nivel mínimo de log
  format?: LogFormat;         // Formato por defecto
  colors?: boolean;           // Colores en consola
  silent?: boolean;           // Desactivar completamente
  useWorker?: boolean;        // Usar worker threads (default: true)
  transports?: Transport[];   // Array de transportes
  metadata?: {                // Metadatos globales
    service?: string;
    version?: string;
    environment?: string;
  };
}

Niveles de Log

trace (0) → debug (1) → info (2) → warn (3) → error (4) → fatal (5)

Estructura de LogEntry

{
  timestamp: Date,
  level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal',
  message: string,
  meta?: any,              // Metadata adicional (puedes incluir tags aquí)
  pid?: number,            // Process ID
  hostname?: string        // Hostname del servidor
}

Transports

1. Console Transport

Escribe en console.log o console.error con soporte para colores.

{
  type: 'console',
  format?: 'text' | 'json',
  colors?: boolean,
  level?: LogLevel
}

Colores disponibles:

  • trace: gris
  • debug: azul
  • info: verde
  • warn: amarillo
  • error: rojo bold
  • fatal: blanco sobre fondo rojo bold

Formato Text:

2025-10-04T20:49:15.588Z [INFO ] Usuario logueado {"userId":123}

Formato JSON:

{"timestamp":"2025-10-04T20:49:15.588Z","level":"info","message":"Usuario logueado","meta":{"userId":123}}

2. File Transport

Escribe en archivos locales con rotación automática on-demand (sin timers).

{
  type: 'file',
  filePath: string,
  format?: 'text' | 'json',
  level?: LogLevel,
  rotation?: {
    type: 'size' | 'date',
    maxSize?: string,        // '10MB', '1GB', etc.
    datePattern?: string,    // 'YYYY-MM-DD', 'YYYY-MM-DD-HH', etc.
    maxFiles?: number,       // Número máximo de archivos a mantener
    compress?: boolean       // Comprimir archivos rotados (.gz)
  }
}

Rotación por Tamaño

La rotación se verifica antes de escribir cada log. Si el archivo excede maxSize, se rota automáticamente.

{
  type: 'file',
  filePath: './logs/app.log',
  rotation: {
    type: 'size',
    maxSize: '10MB',
    compress: true,
    maxFiles: 5
  }
}

Formatos de tamaño soportados:

  • B: Bytes
  • KB: Kilobytes
  • MB: Megabytes
  • GB: Gigabytes

Ejemplos: '10MB', '1.5GB', '500KB'

Proceso:

  1. Antes de escribir un log, verifica el tamaño del archivo actual
  2. Si ≥ maxSize, cierra el stream
  3. Renombra el archivo con timestamp (ej: app.2025-10-04T20-49-15.log)
  4. Si compress: true, comprime a .gz y borra el original
  5. Si maxFiles está configurado, elimina archivos antiguos
  6. Crea un nuevo archivo y escribe el log

Rotación por Fecha

La rotación se verifica antes de escribir cada log comparando el patrón de fecha actual vs. la última rotación.

{
  type: 'file',
  filePath: './logs/daily.log',
  rotation: {
    type: 'date',
    datePattern: 'YYYY-MM-DD',
    compress: true,
    maxFiles: 30  // Mantener 30 días
  }
}

Patrones de fecha soportados:

| Patrón | Frecuencia | Ejemplo | |--------|------------|---------| | YYYY-MM-DD-HH-mm | Cada minuto | 2025-10-04-20-49 | | YYYY-MM-DD-HH | Cada hora | 2025-10-04-20 | | YYYY-MM-DD | Cada día | 2025-10-04 | | YYYY-MM | Cada mes | 2025-10 |

Cómo funciona:

  • El datePattern determina cuándo rotar (comparando strings formateados)
  • También determina el nombre del archivo rotado
  • Ejemplo: con YYYY-MM-DD-HH-mm, rota cada vez que cambia el minuto

Proceso:

  1. Antes de escribir un log, formatea la fecha actual y la última rotación con el patrón
  2. Si los strings son diferentes, el patrón cambió (ej: de 2025-10-04-14 a 2025-10-04-15)
  3. Cierra el stream actual
  4. Renombra el archivo con la fecha (ej: app.2025-10-04-14.log)
  5. Comprime y limpia archivos antiguos si está configurado
  6. Crea un nuevo archivo y escribe el log

3. HTTP Transport

Envía logs a un endpoint HTTP con batching, reintentos automáticos y autenticación.

{
  type: 'http',
  url: string,
  method?: 'POST' | 'PUT',
  level?: LogLevel,
  headers?: Record<string, string>,
  auth?: {
    type: 'bearer' | 'basic' | 'header',
    token?: string,          // Para bearer
    username?: string,       // Para basic
    password?: string,       // Para basic
    headerName?: string,     // Para header custom
    headerValue?: string     // Para header custom
  },
  timeout?: number,          // Timeout en ms (default: 10000)
  retries?: number,          // Número de reintentos (default: 3)
  batchSize?: number,        // Logs por batch (default: 1)
  flushInterval?: number     // Intervalo de flush en ms (default: 5000)
}

Sistema de Batching

Los logs se acumulan y envían en lotes para optimizar el rendimiento:

  • Flush automático: cada flushInterval ms (default: 5000ms)
  • Flush inmediato: cuando el batch alcanza batchSize logs
  • Cola de reintentos: Si falla el envío, los logs van a retryQueue
  • Límite de cola: Máximo 1000 logs para evitar memory leaks

Reintentos con Backoff Exponencial

  • Hasta retries intentos (default: 3)
  • Delay entre reintentos: 2^intento * 1000ms (1s, 2s, 4s...)
  • Si todos los reintentos fallan, los logs quedan en retryQueue

Tipos de Autenticación

Bearer Token:

auth: {
  type: 'bearer',
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
}
// Header generado: Authorization: Bearer eyJhbGc...

Basic Auth:

auth: {
  type: 'basic',
  username: 'user',
  password: 'pass'
}
// Header generado: Authorization: Basic dXNlcjpwYXNz (base64)

Custom Header:

auth: {
  type: 'header',
  headerName: 'X-API-Key',
  headerValue: 'secret-key'
}
// Header generado: X-API-Key: secret-key

Formato de Datos Enviados

Los logs se transforman a JSON antes de enviarse:

Single log:

{
  "timestamp": "2025-10-04T20:49:15.588Z",
  "level": "info",
  "message": "Usuario logueado",
  "meta": { "userId": 123 },
  "pid": 12345,
  "hostname": "server-01"
}

Batch (múltiples logs):

[
  {
    "timestamp": "2025-10-04T20:49:15.588Z",
    "level": "info",
    "message": "Usuario logueado",
    "meta": { "userId": 123 },
    "pid": 12345,
    "hostname": "server-01"
  },
  {
    "timestamp": "2025-10-04T20:49:16.123Z",
    "level": "error",
    "message": "Error al procesar pago",
    "meta": { "errorCode": "PAYMENT_FAILED" },
    "pid": 12345,
    "hostname": "server-01"
  }
]

Headers enviados:

Content-Type: application/json
Authorization: Bearer <token>  (si hay auth)
<custom headers>               (si los configuraste)

Cómo Recibir los Logs en el Servidor

Tu endpoint debe:

  1. Aceptar POST o PUT (según configuración)
  2. Parsear JSON del body
  3. Manejar ambos casos: objeto único o array
  4. Responder con status 2xx para confirmar éxito
  5. Cualquier otro status se considera error y se reintenta

Ejemplo de endpoint Express:

app.post('/logs', (req, res) => {
  const logs = Array.isArray(req.body) ? req.body : [req.body];

  // Validar autenticación
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (token !== 'mi-token-secreto') {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // Procesar logs
  logs.forEach(log => {
    console.log(`[${log.level}] ${log.message}`, log.meta);
    // Guardar en DB, enviar a otro servicio, etc.
  });

  res.status(200).json({ received: logs.length });
});

Flujo de Envío HTTP

Log creado → Batch acumulado → Alcanza batchSize o flushInterval
    ↓
Transformar LogEntry[] a formato JSON
    ↓
Agregar headers (Content-Type, Auth, Custom)
    ↓
Enviar POST/PUT con fetch
    ↓
¿Éxito (2xx)? → ✓ Listo
    ↓
¿Error? → Agregar a retryQueue → Reintentar con backoff exponencial
    ↓
¿Sigue fallando? → Mantener en cola (máx 1000) → Log de error en consola

API

Métodos de Logging

logger.trace(message: string, meta?: any): void
logger.debug(message: string, meta?: any): void
logger.info(message: string, meta?: any): void
logger.warn(message: string, meta?: any): void
logger.error(message: string, meta?: any): void
logger.fatal(message: string, meta?: any): void
logger.log(level: LogLevel, message: string, meta?: any): void

Métodos de Control

await logger.flush(): Promise<void>  // Forzar escritura de buffers pendientes
await logger.close(): Promise<void>  // Cerrar logger y limpiar recursos

Ejemplos Avanzados

Configuración Multi-Transport

const logger = new Mercy({
  level: 'info',
  transports: [
    // Console solo para warnings y errores
    {
      type: 'console',
      level: 'warn',
      colors: true
    },
    // Archivo general con rotación diaria
    {
      type: 'file',
      filePath: './logs/app.log',
      rotation: {
        type: 'date',
        datePattern: 'YYYY-MM-DD',
        maxFiles: 7,
        compress: true
      }
    },
    // Archivo solo para errores con rotación por tamaño
    {
      type: 'file',
      filePath: './logs/errors.log',
      level: 'error',
      rotation: {
        type: 'size',
        maxSize: '50MB',
        maxFiles: 3,
        compress: true
      }
    },
    // HTTP para errores críticos (envío inmediato)
    {
      type: 'http',
      url: 'https://alerts.example.com/webhook',
      level: 'error',
      batchSize: 1,
      auth: {
        type: 'bearer',
        token: process.env.ALERT_TOKEN
      }
    }
  ]
});

Rotación por Hora

const logger = new Mercy({
  transports: [
    {
      type: 'file',
      filePath: './logs/hourly.log',
      rotation: {
        type: 'date',
        datePattern: 'YYYY-MM-DD-HH',  // Rota cada hora
        maxFiles: 24,                   // Mantener 24 horas
        compress: true
      }
    }
  ]
});

HTTP Transport con Batching

const logger = new Mercy({
  transports: [
    {
      type: 'http',
      url: 'https://logs.example.com/api/ingest',
      method: 'POST',
      batchSize: 50,          // Enviar cada 50 logs
      flushInterval: 10000,   // O cada 10 segundos
      timeout: 15000,
      retries: 5,
      auth: {
        type: 'bearer',
        token: process.env.LOG_API_TOKEN
      },
      headers: {
        'X-Service-Name': 'my-app',
        'X-Environment': process.env.NODE_ENV
      }
    }
  ]
});

Configuración por Ambiente

const isDev = process.env.NODE_ENV === 'development';

const logger = new Mercy({
  level: isDev ? 'trace' : 'info',
  silent: process.env.SILENT_LOGS === 'true',
  useWorker: !isDev,  // Worker en producción, directo en desarrollo
  transports: [
    {
      type: 'console',
      colors: isDev,
      level: isDev ? 'trace' : 'warn'
    },
    ...(isDev ? [] : [
      {
        type: 'file',
        filePath: './logs/app.log',
        rotation: {
          type: 'date',
          datePattern: 'YYYY-MM-DD',
          maxFiles: 30,
          compress: true
        }
      },
      {
        type: 'http',
        url: process.env.LOG_ENDPOINT!,
        batchSize: 100,
        auth: {
          type: 'bearer',
          token: process.env.LOG_TOKEN!
        }
      }
    ])
  ]
});

Graceful Shutdown

process.on('SIGINT', async () => {
  console.log('Shutting down gracefully...');
  await logger.flush();  // Asegurar que se envíen todos los logs
  await logger.close();  // Cerrar transports y worker
  process.exit(0);
});

process.on('SIGTERM', async () => {
  await logger.flush();
  await logger.close();
  process.exit(0);
});

Usando Metadata para Tags

// Incluir tags en el campo meta
logger.info('Usuario logueado', {
  tags: ['auth', 'login', 'success'],
  userId: 123,
  ip: '192.168.1.1'
});

logger.error('Pago rechazado', {
  tags: ['payment', 'error', 'critical'],
  errorCode: 'INSUFFICIENT_FUNDS',
  amount: 150.00
});

Worker Thread

El logger puede ejecutarse en un Worker Thread separado para no bloquear el hilo principal.

Mensajes soportados:

  • log - Escribir un log
  • flush - Forzar flush de todos los transports
  • close - Cerrar worker y todos los transports
  • ping - Health check

Respuestas del worker:

  • flushed - Flush completado
  • closed - Worker cerrado exitosamente
  • pong - Respuesta a ping (health check)
  • heartbeat - Worker está vivo (cada 30s)
  • error - Error al procesar mensaje

Características:

  • Health checks cada 60 segundos
  • Reconexión automática (hasta 3 intentos)
  • Fallback a modo directo si falla
  • Timeout de flush: 10 segundos
  • Timeout de close: 5 segundos

Notas Importantes

  1. Worker fallback: Si el worker falla 3 veces, automáticamente cambia a modo directo
  2. Rotación on-demand: Se verifica antes de cada escritura (sin timers en background)
  3. Timeout de flush: 10 segundos máximo
  4. Timeout HTTP: 10 segundos por defecto (configurable)
  5. Cola de reintentos HTTP: Máximo 1000 logs para evitar memory leaks
  6. Health checks: Cada 60 segundos en modo worker
  7. Multiplataforma: Funciona en Windows, Linux y macOS
  8. Timestamps: Usa formato ISO 8601 (2025-10-04T20:49:15.588Z) para legibilidad

Mejoras Sugeridas

Para HTTP Transport

  1. Rate Limiting: Limitar requests por segundo
  2. Confirmación de Recepción: Servidor devuelve IDs de logs recibidos
  3. Circuit Breaker: Pausar envíos si el endpoint falla repetidamente
  4. Metadata Global: Incluir service, version, environment en todos los logs
  5. Webhooks: Notificar cuando se pierden logs por exceder la cola
  6. Chunking Inteligente: Dividir batches muy grandes (>1MB) automáticamente
  7. Formatos Adicionales: Logstash, Syslog, custom serializers

Rendimiento

  • Worker Threads: Logging asíncrono sin bloquear el hilo principal
  • Batching: Agrupación de logs para HTTP transport (reduce overhead)
  • Compresión: Archivos rotados se comprimen automáticamente (ahorra espacio)
  • Recuperación: Workers caídos se reinician automáticamente (hasta 3 veces)
  • Fallback: Si el worker falla, automáticamente cambia a modo directo (sin pérdida de logs)
  • On-demand rotation: Verifica rotación solo al escribir (sin overhead de timers)

Licencia

MIT


Autor

Ramiro Lopez