18 puntos por hongminhee 2025-06-23 | 7 comentarios | Compartir por WhatsApp

Bibliotecas vs aplicaciones: requisitos de logging fundamentalmente distintos

  • Logging de aplicaciones: configuración y gestión explícitas en un entorno que el desarrollador controla directamente
  • Logging de bibliotecas: se integra en proyectos de terceros y necesita respetar el entorno del usuario y su capacidad de elección
  • Límites del enfoque existente: al aplicar loggers centrados en aplicaciones (winston, Pino) a bibliotecas, surge el problema de la imposición
  • El dilema del autor de bibliotecas: ofrecer información de depuración vs no cargar al usuario con más peso

Problemas actuales del logging en bibliotecas

  • Ecosistema de logging fragmentado: Express usa DEBUG=express:*, Mongoose usa mongoose.set('debug', true), etc., cada uno con un método distinto
  • Dilema de dependencias: al usar bibliotecas centradas en aplicaciones como winston o Pino, se imponen al usuario dependencias y configuraciones no deseadas
  • Silencio vs imposición: las dos opciones extremas son renunciar por completo al logging o forzar al usuario a adoptar una forma de logging
  • Complejidad de la inyección de dependencias: es un enfoque más sofisticado, pero aumenta la complejidad de la API y la carga para el usuario

La filosofía "library-first" de LogTape

  • Activación condicional: si el logging no está configurado, no hace absolutamente nada; si se configura, se gestiona de forma integrada
  • Garantía de elección del usuario: la biblioteca no impone una forma de logging y solo se activa cuando el usuario lo desea
  • Cero dependencias: con un tamaño de 5.3KB, elimina riesgos de seguridad en la cadena de suministro y evita conflictos de versiones
  • Soporte completo para ESM/CJS: resuelve problemas en la cadena de compatibilidad y optimiza el bundle mediante tree shaking

Ventajas prácticas

  • Optimización de rendimiento: cuando está desactivado, el overhead es casi cero; cuando está activado, ofrece un excelente rendimiento de salida en consola
  • Separación por namespaces: evita conflictos con categorías jerárquicas en formato ["my-lib", "feature"]
  • Diseño TypeScript-first: ofrece seguridad de tipos completa sin paquetes de tipos adicionales
  • Puente con sistemas existentes: permite una adopción gradual mediante adaptadores para winston y Pino

Consideraciones realistas

  • El sentido de los adaptadores: reconoce que aún no es un estándar del ecosistema y propone un compromiso práctico
  • Inspiración en el ecosistema Python: toma como referencia el caso exitoso de integración de Python con la biblioteca estándar logging
  • Enfoque orientado al futuro: se presenta como una opción para la mejora gradual del ecosistema de bibliotecas

7 comentarios

 
sunrabbit 2025-06-25

No termino de entender cómo se supone que no hace nada cuando no lo configuras.
Cuando haces getLogger, el logger ya se crea y si registras un debug, funciona.

Por lo que vi en el código, más bien solo hace que parezca que no funciona,
y como tampoco retrasa la evaluación de strings,
no termino de entender en qué se diferencia ese “no hacer nada” de otras librerías que simplemente no imprimen nada cuando configuras el nivel de logs.

 
hongminhee 2025-06-25

Vaya, ¿se registran logs aunque no hayas llamado a configure()/configureSync()? ¿Dónde se registran? ¿Se muestran en la consola?

 
sunrabbit 2025-06-26

Ah, a lo que me refería con que funciona aquí no es a que el log se guarde en la consola o en un archivo, sino a si la función se ejecuta y realmente hay sobrecarga.

Es fácil que haya habido un malentendido.

 
sunrabbit 2025-06-26

Por supuesto, considerando que el principal overhead de un logger es la system call, no se puede decir que no haya overhead.
Pero ¿eso realmente lo diferencia de otros loggers? Es difícil decir que sí, porque los demás loggers también funcionan de la misma manera.

 
hongminhee 2025-06-26

Ah, ya veo a qué se refería. Primero, cuando probé el benchmark tomando como referencia la salida nula, parecía que prácticamente no había sobrecarga. Pero, más que la sobrecarga de rendimiento, pensé que lo más importante era si el comportamiento predeterminado era un no-op o no. Desde la perspectiva del autor de una librería, aunque se registren logs dentro de la librería, sería problemático que, cuando se ejecute la aplicación que usa esa librería, los logs se impriman por su cuenta en la consola o en un archivo.

 
sunrabbit 2025-06-26

Ah, era un SHOW GN.
Parece que últimamente en ese ecosistema se elige mucho el enfoque de inyectar el logger desde afuera, así que creo que por eso había partes con las que no conecté.
Si no está configurado, obviamente no funciona.
Aun así, como también es una interfaz de logger que no existía hasta ahora en ese ecosistema y ofrece mucha libertad, me parece mejor.

En el caso del benchmark que compartiste, como imprime una salida nula excluyendo las system calls,
sí creo que esta parte puede variar claramente según la forma del logger interno.

En este punto, le saca hasta una diferencia de tres veces a Pino. Je.


FYI: además, la forma de logger inyectado desde afuera que mencioné se puede verificar fácilmente incluso viendo solo el SDK de OpenAI para Node, ya que tiene una forma de recibir el logger externamente y emitir la salida.