Logging con Pino en Astro
Aprende a implementar un sistema de logging robusto con Pino para registrar eventos, errores y auditoría en tus aplicaciones Astro.
1 ¿Qué es Logging?
Logging es el proceso de registrar eventos, mensajes y errores que ocurren durante la ejecución de una aplicación. Estos registros se guardan típicamente en archivos de texto o sistemas de bases de datos para análisis posterior.
📓 Analogía del mundo real:
Logging es como un diario de eventos. Así como un capitán de barco registra en el cuaderno de bitácora qué sucedió durante el viaje (cambios de rumbo, problemas encontrados, observaciones importantes), tu aplicación registra qué está sucediendo en cada momento.
Componentes básicos de un log:
- • Timestamp: Cuándo ocurrió el evento
- • Nivel: Importancia del evento (error, warning, info, debug)
- • Mensaje: Descripción de lo que sucedió
- • Contexto: Información adicional relevante (usuario, ID de sesión, etc.)
2 ¿Para Qué Se Usa Logging?
🐛 Debugging (Depuración)
Identificar y solucionar problemas en el código. Los logs te muestran exactamente qué sucedió antes de que ocurriera un error.
📊 Monitoreo de Aplicación
Supervisar el rendimiento y comportamiento de la aplicación en producción. Detectar anomalías o patrones inusuales.
🔐 Auditoría y Seguridad
Registrar acciones importantes como login de usuarios, cambios de datos, accesos no autorizados. Cumplimiento normativo.
🔍 Investigación de Incidentes
Reconstruir la secuencia de eventos que llevó a un problema. Análisis histórico de errores y comportamientos anómalos.
3 ¿Por Qué Usar Pino?
Pino es una librería de logging para Node.js enfocada en rendimiento y facilidad de uso. Es la elección preferida en aplicaciones modernas de Node.js.
Súper Rápido
Una de las librerías de logging más rápidas disponibles. Impacto mínimo en rendimiento.
JSON Estructurado
Los logs se generan en formato JSON, ideal para parsear y analizar automáticamente.
API Simple
Interfaz intuitiva y fácil de usar. Se aprende rápidamente.
Soporte para Transports
Envía logs a archivos, bases de datos, o servicios de terceros fácilmente.
Niveles de Log
Control granular sobre qué tipo de mensajes registrar (trace, debug, info, warn, error, fatal).
4 Instalación y Configuración Básica
Paso 1: Instalar Pino
1npm install pino2# Opcional: para escribir en archivos3npm install pino-prettyPaso 2: Crear archivo de configuración
Crea un archivo src/utils/logger.ts para centralizar la configuración:
1import pino from 'pino';2import { fileURLToPath } from 'url';3import { dirname, join } from 'path';4 5// Obtener directorio actual (necesario en ES modules)6const __filename = fileURLToPath(import.meta.url);7const __dirname = dirname(__filename);8 9// Determinar si estamos en desarrollo o producción10const isDev = process.env.NODE_ENV !== 'production';11 12// Configurar opciones de Pino13const pinoConfig = {14 // Nivel de log mínimo15 level: isDev ? 'debug' : 'info',16 // Configuración de timestamp17 timestamp: pino.stdTimeFunctions.isoTime,18};19 20// En desarrollo, usar pretty-print para mejor legibilidad21const transport = isDev22 ? pino.transport({23 target: 'pino-pretty',24 options: {25 colorize: true,26 translateTime: 'SYS:standard',27 ignore: 'pid,hostname',28 singleLine: false,29 },30 })31 : undefined;32 33// Crear instancia de logger34const logger = pino(pinoConfig, transport);35 36export default logger;Paso 3: Usar el logger en tu aplicación
1// En cualquier archivo Astro o ruta API2import logger from '@/utils/logger';3 4logger.info('Aplicación iniciada');5logger.warn('Esto es una advertencia');6logger.error('Algo salió mal');7logger.debug('Información de debugging');5 Niveles de Log
Pino ofrece 6 niveles de severidad. Cada nivel tiene un número asociado para filtrado:
| Nivel | Número | Uso | Ejemplo |
|---|---|---|---|
| fatal | 60 | Error crítico que detiene la aplicación | Base de datos no disponible |
| error | 50 | Error en la ejecución | Excepción no capturada |
| warn | 40 | Situación anormal pero no es un error | API deprecada, recurso agotado |
| info | 30 | Información general de la aplicación | Usuario autenticado, request procesado |
| debug | 20 | Información detallada para debugging | Variables intermedias, flujo de ejecución |
| trace | 10 | Información más detallada (rara vez usado) | Stack traces completos, datos raw |
💡 Consejo de Producción:
En producción, configura el nivel a info o superior.
Los logs de debug y trace generan mucho volumen y afectan rendimiento.
6 Escribir Logs en Archivos
Usando pino-roll (rotación automática)
Para producción, es recomendable usar pino-roll para rotar logs automáticamente:
1npm install pino-rollActualizar tu configuración:
1import pino from 'pino';2import { fileURLToPath } from 'url';3import { dirname, join } from 'path';4 5const __filename = fileURLToPath(import.meta.url);6const __dirname = dirname(__filename);7 8const isDev = process.env.NODE_ENV !== 'production';9 10// Directorio para logs11const logsDir = join(__dirname, '../../logs');12 13const pinoConfig = {14 level: isDev ? 'debug' : 'info',15 timestamp: pino.stdTimeFunctions.isoTime,16};17 18let transport;19 20if (isDev) {21 // En desarrollo: pretty-print en consola22 transport = pino.transport({23 target: 'pino-pretty',24 options: {25 colorize: true,26 translateTime: 'SYS:standard',27 ignore: 'pid,hostname',28 },29 });30} else {31 // En producción: escribir en archivos con rotación32 transport = pino.transport({33 targets: [34 {35 level: 'info',36 target: 'pino-roll',37 options: {38 file: join(logsDir, 'app.log'),39 frequency: 'daily', // Rotar diariamente40 size: '10m', // O rotar cada 10MB41 mkdir: true,42 },43 },44 {45 level: 'error',46 target: 'pino-roll',47 options: {48 file: join(logsDir, 'error.log'),49 frequency: 'daily',50 mkdir: true,51 },52 },53 ],54 });55}56 57const logger = pino(pinoConfig, transport);58 59export default logger;7 Ejemplos Prácticos con Astro
Ejemplo 1: Logging en una ruta API
1// src/pages/api/users.ts2import type { APIRoute } from 'astro';3import logger from '@/utils/logger';4 5export const GET: APIRoute = async ({ request }) => {6 logger.info(`Recibido GET request: ${request.url}`);7 8 try {9 // Simular obtención de usuarios10 const users = [11 { id: 1, name: 'Alice', email: 'alice@example.com' },12 { id: 2, name: 'Bob', email: 'bob@example.com' },13 ];14 15 logger.debug('Usuarios obtenidos del recurso', { count: users.length });16 17 return new Response(JSON.stringify(users), {18 status: 200,19 headers: { 'Content-Type': 'application/json' },20 });21 } catch (error) {22 logger.error('Error al obtener usuarios', {23 error: error instanceof Error ? error.message : String(error)24 });25 26 return new Response(JSON.stringify({ error: 'Internal Server Error' }), {27 status: 500,28 headers: { 'Content-Type': 'application/json' },29 });30 }31};Ejemplo 2: Logging de eventos importantes
1// src/pages/api/auth/login.ts2import type { APIRoute } from 'astro';3import logger from '@/utils/logger';4 5export const POST: APIRoute = async ({ request }) => {6 const body = await request.json() as { email: string; password: string };7 8 logger.info('Intento de login', { email: body.email });9 10 try {11 // Validar credenciales (simulado)12 const isValid = body.email && body.password.length >= 6;13 14 if (!isValid) {15 logger.warn('Login fallido - credenciales inválidas', { email: body.email });16 17 return new Response(JSON.stringify({ error: 'Invalid credentials' }), {18 status: 401,19 });20 }21 22 // Simular crear sesión23 const sessionId = 'sess_' + Math.random().toString(36).substr(2, 9);24 25 logger.info('Login exitoso', {26 email: body.email,27 sessionId,28 timestamp: new Date().toISOString()29 });30 31 return new Response(JSON.stringify({ sessionId, email: body.email }), {32 status: 200,33 });34 } catch (error) {35 logger.error('Error en login', {36 email: body.email,37 error: error instanceof Error ? error.message : String(error)38 });39 40 return new Response(JSON.stringify({ error: 'Server error' }), {41 status: 500,42 });43 }44};8 Buenas Prácticas
Usa niveles apropiados
No registres todo como info. Usa debug para información detallada.
Agrega contexto relevante
Incluye IDs de usuario, transacciones y valores importantes que ayuden a entender qué sucedió.
No registres datos sensibles
Nunca escribas contraseñas, tokens o números de tarjeta en logs.
Implementa rotación de logs
En producción, usa pino-roll para rotar logs. Evita archivos gigantes.
No uses console.log en producción
console.log no es estructurado y no se guarda. Siempre usa Pino.
Monitorea el volumen de logs
Los logs en exceso pueden afectar rendimiento. Usa niveles apropiados en producción.
9 Resumen
- • Logging es registrar eventos de tu aplicación para debugging, monitoreo y auditoría.
- • Pino es una librería rápida, eficiente y fácil de usar para logging en Node.js y Astro.
- • Usa los 6 niveles de log (trace, debug, info, warn, error, fatal) apropiadamente según la severidad.
- • Agrega contexto a los logs para hacerlos más útiles en debugging y monitoreo.
- • En producción, configura rotación automática de logs con pino-roll.
- • Nunca registres datos sensibles (contraseñas, tokens, números de tarjeta) en logs.