¿Qué es el registro de eventos?

Cuando ocurre un fallo en una aplicación, un desarrollador experimentado pregunta primero: "¿Qué hay en los registros?". Aprendamos qué es el registro de eventos y cómo analizar los registros.
Es bien sabido que los programadores pasan mucho tiempo depurando sus programas, tratando de entender por qué no funcionan o funcionan incorrectamente. Cuando se habla de depuración, generalmente se refiere a la impresión de depuración o al uso de programas especiales, como depuradores. Estos métodos funcionan bien en programas pequeños, pero se vuelven ineficientes rápidamente en aplicaciones reales.
La complejidad de las aplicaciones reales
Tomemos como ejemplo un sitio web típico. ¿Qué incluye?
  • DNS. Un sistema que traduce el nombre del sitio web en la dirección IP del servidor.
  • Servidor web. Un programa que maneja las solicitudes entrantes, las redirige al código de la aplicación y recupera datos de la aplicación para los usuarios.
  • Servidor físico (o virtual) con su entorno. Incluye un sistema operativo, programas de servicio instalados y en ejecución, como monitoreo.
  • Base de datos. Un almacenamiento externo con el que el código de la aplicación se comunica e intercambia información.
  • La propia aplicación. Además del código escrito por los programadores, la aplicación incluye cientos de miles y millones de líneas de código de bibliotecas de terceros. Además, el código se ejecuta dentro de un marco que tiene sus propias reglas para procesar las solicitudes entrantes.
  • Parte del frontend. Código que se ejecuta en el navegador del usuario. Y sistemas de compilación para el desarrollo, como Webpack.
Y este es solo el caso más simple. La realidad es mucho más complicada: muchos servidores de diferentes tipos, sistemas de almacenamiento en caché (aceleración de acceso), código asíncrono, colas, servicios externos, servicios en la nube. Todo esto se parece a una tarta de múltiples capas, dentro de la cual nuestro código escrito por nosotros está en algún lugar. Y este código es solo una pequeña parte de todo lo que está sucediendo. En esta situación, ¿cómo entender en qué etapa ocurrió el fallo o qué salió mal? Para hacer esto, como mínimo, es necesario determinar en qué capa se produjo el error. Pero eso no es lo más difícil. Los errores en una aplicación en funcionamiento no se conocen de inmediato, sino después, cuando el error ha ocurrido y, a veces, ya no se puede reproducir.
Registro de eventos
Para toda esta diversidad de sistemas, existe una solución única: el registro de eventos. En el caso más simple, el registro de eventos se reduce a un archivo en el disco donde los diferentes programas registran sus acciones durante la ejecución. A este archivo se le llama registro o bitácora. Por lo general, dentro del registro, una línea corresponde a una acción.

# Formato: dirección IP / fecha / método HTTP / URI / código de respuesta / tamaño del cuerpo
173.245.52.110 - [19/ene/2021:01:54:20 +0000] "GET /my HTTP/1.1" 200 46018
108.162.219.13 - [19/ene/2021:01:54:20 +0000] "GET /sockjs-node/244/gdt1vvwa/websocket HTTP/1.1" 0 0
162.158.62.12 - [19/ene/2021:01:54:20 +0000] "GET /packs/css/application.css HTTP/1.1" 304 0
162.158.62.84 - [19/ene/2021:01:54:20 +0000] "GET /packs/js/runtime-eb0a99abbe8cf813f110.js HTTP/1.1" 304 0
108.162.219.111 - [19/ene/2021:01:54:20 +0000] "GET /packs/js/application-2cba5619945c4e5946f1.js HTTP/1.1" 304 0
108.162.219.21 - [19/ene/2021:01:54:20 +0000] "GET /packs/js/0564a7b5d773bab52e53.js HTTP/1.1" 304 0
108.162.219.243 - [19/ene/2021:01:54:20 +0000] "GET /packs/js/6fb7e908211839fac06e.js HTTP/1.1" 304 0
Arriba hay un fragmento del registro del servidor web de Códica. Muestra la dirección IP desde la que se realizó la solicitud de la página y qué recursos se cargaron, el método HTTP, la respuesta del backend (código) y el tamaño del cuerpo de la respuesta HTTP. Es muy importante tener la fecha. Gracias a ella, siempre se puede encontrar el registro para un período específico, por ejemplo, cuando ocurrió un error. Para hacer esto, los registros se filtran:

# Mostrará 4 minutos de registros para el 31 de marzo de 2020 de 19:31 a 19:35
grep "31/Mar/2020:19:3[1-5]" access.log
Cuando los programadores comienzan su camino, a menudo, sin saber la causa del error, se rinden y dicen "no sé qué pasó y qué hacer". Sin embargo, un desarrollador experimentado siempre pregunta primero "¿qué hay en los registros?". Analizar los registros es una de las habilidades básicas en el desarrollo. En cualquier situación confusa, es necesario mirar los registros. Todos los programas registran eventos sin excepción, pero lo hacen de diferentes maneras y en diferentes lugares. Para saber exactamente dónde y cómo, es necesario consultar la documentación del programa específico y leer la sección correspondiente de la documentación. Aquí hay algunos ejemplos:
Muchos programas registran directamente en la consola, por ejemplo, Webpack muestra el proceso y los resultados de la compilación:

# También muestra errores si los hay
「wds」: Project is running at https://codicadev4.com/
「wds」: webpack output is served from /packs/
「wds」: Content not from webpack is served from /root/codica/public/packs
「wds」: 404s will fallback to /index.html
「wdm」: assets by chunk 10.8 MiB (auxiliary name: application) 115 assets
sets by path js/ 13.8 MiB
assets by path js/*.js 13.8 MiB 52 assets
assets by path js/pages/*.js 5.1 KiB
  asset js/pages/da223d3affe56711f31f.js 2.6 KiB [emitted] [immutable] (name: pages/my_learning) 1 related asset
  asset js/pages/04adacfdd660803b19f1.js 2.5 KiB [emitted] [immutable] (name: pages/referral) 1 related asset
sets by chunk 9.14 KiB (auxiliary id hint: vendors)
En el frontend, no hay archivos, por lo que se registran directamente en la consola, o se envían a los backends (lo cual es complicado), o se envían a servicios especializados, como LogRocket.
Niveles de registro
Cuanta más información se muestre en los registros, mejor y más fácil será la depuración, pero cuando hay demasiados datos, es difícil encontrar lo que se necesita. En casos especialmente complejos, los registros pueden generarse a una velocidad enorme y tener un tamaño gigantesco. Trabajar en una situación así no es fácil. Para suavizar la situación, los sistemas de registro introducen diferentes niveles. Por lo general, son:
  • debug
  • info
  • warning
  • error
El soporte para niveles se realiza de dos maneras. En primer lugar, dentro del propio programa, se colocan llamadas a la biblioteca de registro de acuerdo con los niveles. Si se produce un error, se registra como error, si es información de depuración que no es necesaria en una situación normal, se utiliza el nivel debug.

// Ejemplo de registro dentro del programa
// Biblioteca de registro: https://github.com/pinojs/pino

import buildLogger from 'pino';

const logger = buildLogger(/* posible configuración */);
logger.info('algo útil aquí');
En segundo lugar, durante la ejecución del programa, se especifica el nivel de registro necesario para una situación específica. Por defecto, se utiliza el nivel info, que se utiliza para describir cosas clave e importantes. Con este nivel, se mostrarán tanto warning como error. Si se establece el nivel error, solo se mostrarán los errores. Y si se establece debug, obtendremos un registro lleno de datos. Por lo general, debug conduce a un aumento múltiple de la información mostrada.

Los niveles de registro generalmente se establecen a través de una variable de entorno durante la ejecución del programa. Por ejemplo, así:

# https://github.com/fastify/fastify-cli#options
FASTIFY_LOG_LEVEL=debug fastify-server.js
También existe otro enfoque basado no en niveles, sino en espacios de nombres. Este enfoque se ha generalizado en el entorno de JavaScript y es el principal allí. De hecho, se basa en una única biblioteca de registro debug, que está presente en casi todas las bibliotecas de JavaScript, tanto en el frontend como en el backend.
El principio de funcionamiento es el siguiente. Para una situación específica, se crea una función de registro especializada con un espacio de nombres especificado, que luego se utiliza para todos los eventos de un solo proceso. Como resultado, la biblioteca permite filtrar fácilmente solo los registros necesarios que corresponden al espacio de nombres necesario.

import debug from 'debug';

// Espacio de nombres http
const logHttp = debug('http');
const logSomethingElse = debug('another-namespace');

// En algún lugar del código

logHttp(/* información sobre la solicitud HTTP */);
Ejecución con el espacio de nombres necesario:

DEBUG=http server.js
Rotación de registros
Con el tiempo, la cantidad de registros se vuelve grande y algo debe hacerse con ellos. Para esto se utiliza la rotación de registros. A veces, el propio programa se encarga de esto, pero más a menudo es una aplicación externa cuya tarea es limpiar. Este programa divide los registros en archivos más pequeños según sea necesario, los comprime, los mueve y, si es necesario, los elimina. Un sistema similar está incorporado en cualquier sistema operativo para trabajar con los registros del propio sistema y de programas externos que pueden integrarse en él.

Con los sitios web, la situación es aún más complicada. Incluso en proyectos pequeños, se utilizan varios servidores, cada uno con sus propios registros. Y en proyectos grandes, hay miles de servidores. Para administrar tales sistemas, se crearon programas especializados que monitorean los registros en todas las máquinas, los descargan, los almacenan en bases de datos optimizadas para registros y proporcionan una forma conveniente de buscar en ellos.

Aquí también hay varias formas de hacerlo. Puedes utilizar soluciones listas para usar, como DataDog Logging, o instalar y configurar todo tú mismo a través de, por ejemplo, ELK Stack.
Leer otros artículos de Guías
Lea otros artículos relevantes del mundo de la tecnología y el espíritu empresarial.