En entornos de producción con múltiples nodos de Nginx, la revisión manual de los archivos de errores (error.log) puede resultar inviable. En este artículo, detallamos cómo diseñar e implementar una solución de monitorización automatizada utilizando un Playbook de Ansible y un Script de Python integrado. El sistema recordará la última posición leída en el log (evitando procesar datos repetidos), agrupará los errores, registrará una auditoría local del proceso y enviará un único correo por nodo en caso de anomalías.

Arquitectura y componentes clave para automatización de lectura de log Nginx con Ansible

Para automatizar tareas con Ansible, necesitaremos disponer de un servidor con Ansible/Sempahore, en el siguiente tutorial explicamos cómo desplegarlo:

El despliegue de esta automatización se divide en tres capas técnicas:

  1. Gestión de inventario dinámico (Ansible): permite parametrizar las rutas específicas de los archivos de log de manera independiente para cada nodo o balanceador Nginx.
  2. Lógica de análisis de logs (Python): desde el playbook de Ansible se generará un script de Python que realiza una lectura secuencial a partir de la última posición conocida (offset). Utiliza expresiones regulares (re) para extraer el error, descartando las variables mutables del formato de Nginx (como PID o marcas de tiempo). De esta manera, si un error ocurre muchas veces, se almacena en memoria como una sola clave única.
  3. Auditoría e historial local: tanto el script de Python como el orquestador Ansible interactúan directamente con el sistema de archivos local (/var/log/nginx_monitor.log) utilizando elevación de privilegios (become: yes) para registrar cuándo comenzó el análisis, cuántas líneas se procesaron y el estado exacto del envío de alertas por correo SMTP.

Paso 1: Configurar el inventario de Ansible (Hosts y variables)

El primer paso configuraremos Ansible/Semaphore añadiendo el inventario de hosts (nodos de Nginx a monitorizar) y las variables de cada nodo (ruta del fichero de error.log) y variables de servidor SMTP para envío de email.

En este estudio de caso, cada servidor Linux con Nginx tiene el fichero de error.log con un nombre diferente, por ello, estableceremos en su inventario, en la declaración de cada host, en variable error_log_path, la ruta del fichero de error.log. Desde Ansible/Sempahore, en «Inventario», añadiremos un nuevo inventario:

En el nuevo inventario de servidores, añadiremos, en formato INI, los servidores que queramos automatizar. En este ejemplo, tenemos un grupo de servidores de Nginx (servidores_nginx) y otro grupo servidores_bd, aplicaremos la automatización solo al grupo servidores_nginx:

Nota: si en algún nodo Nginx no se define la variable error_log_path, se tomará la ruta de error.log por defecto.

Por otro lado, definiremos las variables con los datos del servidor de SMTP para envío de email (usuario, contraseña, puerto, servidor, emisor, destinatario, etc.). Para ello, desde «Grupos de Variables», pulsaremos en «Nuevo grupo»:

Introduciremos un nombre para el grupo de variables, por ejemplo «servidor_email», y añadiremos las siguientes variables con sus valores correspondientes: smtp_user, smtp_pass, email_from, email_to, smtp_host y smtp_port.

Paso 2: El Playbook de Ansible para automatizar lectura de log Nginx y envío de email

En el servidor de Ansible, si tenemos playbook locales, crearemos un fichero de playbook, con formato YAML, llamado comprobar_errores_nginx.yml. Este archivo coordina el despliegue del script, su ejecución como súper usuario, el parseo de datos estructurados en formato JSON y el control de flujos para el envío del correo. Pegaremos el siguiente contenido:

Guardaremos el fichero de playbook en la carpeta que tengamos establecida para tal propósito:

Explicación detallada del playbook

1. Hosts objetivos del playbook

En la sección Hosts del playbook hemos definido servidores_nginx. Esta línea es muy importante porque en ella estamos definiendo que el playbook se ejecute sólo en el grupo de servidores servidores_nginx, que definimos en el inventario anteriormente. En caso establecer all en Hosts, el playbook se ejecutará en todos los servidores indicados en el inventario asignado a la tarea que ejecuta este playbook.

2. El Control de desplazamiento (Offset)

Leer archivos de gigabytes de tamaño de arriba a abajo en cada ejecución consume CPU e I/O de manera innecesaria. El script mitiga esto utilizando la función nativa de Python f.seek(last_position). Al final del escaneo, f.tell() captura la posición exacta en bytes donde terminó la lectura y la almacena en un archivo JSON local (/tmp/nginx_log_state.json). La siguiente vez que corre el playbook, la lectura comienza directamente desde ese byte exacto.

3. Gestión de la Rotación del Log (Logrotate)

¿Qué pasa si el sistema operativo compacta y vacía el log a medianoche? El script lo controla mediante una validación matemática simple:

Si el tamaño actual del archivo en disco es menor que la posición guardada en el historial, significa que el archivo ha sido rotado o truncado. El script reinicia automáticamente el puntero a cero (0) evitando la pérdida de lecturas o errores de desbordamiento.

4. De-duplicación por expresiones regulares

Una línea típica de error en Nginx tiene metadatos dinámicos, por ejemplo:

Si la IP genera varias peticiones fallidas idénticas, las marcas de tiempo y los ID de conexión (*98765) cambiarán en cada línea de manera constante. Nuestra expresión regular elimina esos metadatos cambiantes:

Al aislar la cadena (connect() failed...), el script la utiliza como una clave de diccionario (unique_errors[error_core] = line_str). Python descarta de forma automática las entradas anteriores repetidas y mantiene únicamente el último evento registrado en el bloque leído.

5. Escalado de privilegios (become: yes) y buenas prácticas

Uso de Ansible Facts nativos: en cumplimiento con las directivas modernas de desarrollo de Ansible (evitando los Deprecation Warnings de inyección de variables globales), se invoca al diccionario estructurado ansible_facts (ej. {{ ansible_facts['hostname'] }}) en lugar de la sintaxis obsoleta {{ ansible_hostname }}. Esto blinda nuestra automatización para que sea compatible con las futuras versiones de ansible-core.

Elevación de privilegios: aunque el usuario del sistema encargado de ejecutar la automatización (en este caso, anb_sru) tiene reglas sudoers habilitadas, Ansible necesita explícitamente el parámetro become: yes en las tareas de ejecución y en la inyección de líneas con lineinfile. Esto asegura que se posean los privilegios de lectura sobre el directorio restringido /var/log/nginx/ y permisos de escritura para auditar localmente en /var/log/nginx_monitor.log.

Paso 3: Crear tarea en Ansible/Semaphore para ejecutar playbook

En Ansible/Semaphore, crearemos una nueva tarea, desde «Plantillas de Tareas» – «Nueva plantilla», elegiremos «Ansible Playbook»:

Introduciremos los siguientes datos para la plantilla de tarea:

  • Nombre: comprobar_errores_nginx.
  • Ruta al archivo de playbook: comprobar_errores_nginx.yml.
  • Inventario: Servidores_linux. En este caso, aunque en este grupo de inventario tengamos otros servidores, solo cogerá los del grupo indicado en el playbook (hosts): servidores_nginx.
  • Repositorio: Local.
  • Grupos de Variables: elegiremos el grupo creado anteriormente «servidor_email».

Ejecutar playbook y creación de programación para ejecución periódica

Realizaremos una primera prueba de ejecución, desde «Plantilla de Tareas», pulsaremos en «Play» en la tarea creada:

Se lanzará la ejecución, Ansible conectará con cada nodo/servidor del grupo servidores_nginx, definido en el inventario «servidores_linux», creará el script Python, lo ejecutará y realizará la tarea indicada de lectura de fichero error.log y, si detecta nuevos errores, envío de email:

En cada servidor, habrá creado un fichero de log con el resultado de la ejecución del playbook:

Si alguno de los ficheros access.log de algún nodo tiene errores nuevos, recibiremos un email con los datos del nodo y e lerror:

Una vez revisado el playbook, cuando funcione correctamente, añadiremos la programación oportuna en Semaphore para que el playbook se ejecute cada cierto tiempo. Para ello, desde «Hoorario», pulsaremos en «Nuevo horario» y en «Cron»:

Elegiremos el Template «comprobar_errores_nginx» y estableceremos el Timing, por ejemplo, ejecutaremos la automatización cada 10 minutos:

A partir de ahora, la automatización se ejecutará cada 10 minutos en todos los servidores.