Volver al inicio
Anexo: Logging con Pino

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 pino
2# Opcional: para escribir en archivos
3npm install pino-pretty

Paso 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ón
10const isDev = process.env.NODE_ENV !== 'production';
11
12// Configurar opciones de Pino
13const pinoConfig = {
14 // Nivel de log mínimo
15 level: isDev ? 'debug' : 'info',
16 // Configuración de timestamp
17 timestamp: pino.stdTimeFunctions.isoTime,
18};
19
20// En desarrollo, usar pretty-print para mejor legibilidad
21const transport = isDev
22 ? 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 logger
34const logger = pino(pinoConfig, transport);
35
36export default logger;

Paso 3: Usar el logger en tu aplicación

1// En cualquier archivo Astro o ruta API
2import 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-roll

Actualizar 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 logs
11const 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 consola
22 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ón
32 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 diariamente
40 size: '10m', // O rotar cada 10MB
41 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.ts
2import 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 usuarios
10 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.ts
2import 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ón
23 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.
← Anterior: Generar PDFs Volver a Anexos →