Como realizar analisis de eventos en archivos de registro logs de correo Postfix con Python

En esta entrada, escribiré cómo utilizar un script de Python para analizar archivos de registro de correo de Postfix, y cómo presentar los resultados en una tabla fácil de leer que muestre los promedios diarios, semanales, mensuales y anuales de los eventos clave. Con esta información, podrás tomar decisiones informadas para mejorar la calidad del servicio y resolver problemas en tu servidor de correo.

El monitoreo y análisis de eventos en servidores de correo es fundamental para garantizar un rendimiento óptimo y detectar posibles problemas. En este artículo, exploraremos cómo analizar los archivos de registro de correo generados por Postfix, uno de los agentes de transferencia de correo (MTA) más populares en la actualidad. En particular, nos centraremos en eventos clave, como la entrega de correos (delivered), recepción de correos (received), correos rebotados (bounced), correos rechazados (rejected) y correos diferidos (deferred). Estos eventos pueden ayudarnos a identificar problemas como fallas en la entrega, intentos de spam o problemas en la configuración de nuestro servidor de correo.

Por ejemplo, cuando Postfix entrega exitosamente un correo electrónico, genera un evento "delivered" en el archivo de registro. De manera similar, cuando un correo electrónico entrante es rechazado debido a razones como listas negras o fallas en la autenticación, se registra un evento "rejected". Al analizar la frecuencia de estos eventos en nuestros archivos de registro, podemos obtener información valiosa sobre el estado y el rendimiento de nuestro servidor de correo.

Antes de empezar, no te preocupes si no sabes python, entendemos que puedes no tener conocimiento de python, pero para ellos, trataremos de darte una explicación del script y ademas te mostraremos como utilizar el script.

En Linux el concepto de extensiones es mas un simple referencia que utilizamos para saber que tiene dentro ese archivo, por ejemplo (script_estadístico_log_postfix.py) si es un programa en python, el nombre del archivo se suele terminar con .py , pero el sistema operativo no la utiliza.

Script estadístico : Una vez copiado y pegado de python en un mismo archivo script_estadístico_log_postfix.py

#!/usr/bin/env python 
# -*- coding: utf-8 -*-
import re
from collections import defaultdict
from datetime import datetime, timedelta

filename = '/var/log/mail.log'

file = open(filename, 'r')
log_data = file.readlines()
file.close()

event_pattern = re.compile(
r'\b(received|delivered|forwarded|deferred|bounced|rejected|reject warnings|held|discarded)\b', re.IGNORECASE)

date_pattern = re.compile(r'\b\w{3} \d{1,2} \d{2}:\d{2}:\d{2}\b')

events = defaultdict(int)
dates = set()

for line in log_data:
date_match = date_pattern.search(line)
if date_match:
date_str = date_match.group()
dates.add(date_str)

event_match = event_pattern.search(line)
if event_match:
event = event_match.group().lower()
events[event] += 1

min_date_str = min(dates)
max_date_str = max(dates)

min_date = datetime.strptime(min_date_str, '%b %d %H:%M:%S')
max_date = datetime.strptime(max_date_str, '%b %d %H:%M:%S')

delta_days = abs((max_date - min_date).days) + 1

header_format = "%-15s %10s %10s %10s %10s"
row_format = "%-15s %10.2f %10.2f %10.2f %10.2f"

event_translations = {
'delivered': 'Entregados',
'received': 'Recibidos',
'bounced': 'Rebotados',
'rejected': 'Rechazados',
'deferred': 'Diferidos'
}

print("Resumen desde %s hasta %s:" % (min_date_str, max_date_str))
print(header_format % ("Eventos", "Diario", "Semanal", "Mensual", "Anual"))

for event, count in events.items():
daily = float(count) / delta_days
weekly = float(count) / (delta_days / 7.0)
monthly = float(count) / (delta_days / 30.0)
yearly = float(count) / (delta_days / 365.0)

translated_event = event_translations.get(event, event).capitalize()
print(row_format % (translated_event, daily, weekly, monthly, yearly))

Ejecutar el script

Para ejecutar el script, sigue estos pasos:

  1. Copia el código del script proporcionado en un archivo de texto y guárdalo con la extensión .py, por ejemplo, script_estadístico_log_postfix.py.
  2. Abre una terminal en tu computadora.
  3. Navega hasta la ubicación donde guardaste el archivo script_estadístico_log_postfix.py. Por ejemplo, si lo guardaste en la carpeta "Descargas" del usuario user1, puedes ejecutar este comando en la terminal: cd Descargas
 user1@servidor_correo:/home/user1$ cd Descargas
  1. Asegúrate de que Python esté instalado en tu sistema. Puedes verificar si está instalado ejecutando este comando en la terminal:
 python --version

Si no está instalado, puedes descargarlo e instalarlo desde el manejador de paquetes de la distribución "apt install python" o desde el sitio web oficial de Python: https://www.python.org/downloads/

  1. Dado que el script intenta leer el archivo /var/log/mail.log, es posible que necesites ejecutar el script con privilegios de superusuario (root). Para hacerlo, ejecuta el siguiente comando en la terminal:
sudo python script_estadístico_log_postfix.py

Si no necesitas privilegios de superusuario, puedes ejecutar el script sin sudo:

python script_estadístico_log_postfix.py

Una vez que se ejecute el script, deberías ver el resumen estadístico diario, semanal, mensual y anual de los correos en la terminal.

 user1@servidor_correo:/home/user1$ sudo python script_estadístico_log_postfix.py

Resumen desde Apr 10 00:00:02 hasta Mar 31 23:59:58:

Eventos             Diario    Semanal    Mensual      Anual
Entregados        10685.64   74799.45  320569.09 3900257.27
Recibidos           704.09    4928.64   21122.73  256993.18
Rebotados            15.55     108.82     466.36    5674.09
Rechazados         4504.55   31531.82  135136.36 1644159.09
Diferidos          1582.09   11074.64   47462.73  577463.18

Ten en cuenta que estos pasos son aplicables a sistemas basados en Linux y macOS. Si estás utilizando Windows, el proceso puede variar ligeramente.

Explicación del Script segun las bibliotecas, funciones y operaciones utilizadas por lineas:

Sabiendo que este script analiza un archivo de registro de correo y muestra un resumen de los eventos encontrados (entregados, recibidos, rebotados, rechazados y diferidos) con promedios diarios, semanales, mensuales y anuales. su explicación por linea :

Lineas agregadas 1: #!/usr/bin/env python la agregue después para indicarle el interprete de python por defecto
Lineas agregadas 2: # -*- coding: utf-8 -*- la agregue después para indicarle la codificación del texto a utilizar

Linea 1: import re: Importa el módulo re (expresiones regulares) para buscar patrones en el texto.

Linea 2: from collections import defaultdict: Importa defaultdict de la biblioteca collections. Un defaultdict es un tipo especial de diccionario que asigna un valor predeterminado cuando se intenta acceder a una clave que no existe.

Linea 3: from datetime import datetime, timedelta: Importa las clases datetime y timedelta del módulo datetime para trabajar con fechas y horas.

Linea 4filename = '/var/log/mail.log': Define la ruta del archivo de registro de correo.

Linea 5 file = open(filename, 'r'): Abre el archivo en modo lectura y lo guarda en la variable file.

Linea 6 log_data = file.readlines(): Lee todas las líneas del archivo y las guarda en una lista llamada log_data.

Linea 7 file.close(): Cierra el archivo.

Linea 8 event_pattern = re.compile(...): Compila una expresión regular que busca los eventos de interés en cada línea del archivo de registro de correo.

Linea 9 date_pattern = re.compile(...): Compila una expresión regular que busca fechas en cada línea del archivo de registro de correo.

Linea 10 events = defaultdict(int): Crea un defaultdict que asignará el valor 0 a las claves no existentes. Esto se utilizará para contar los eventos.

Linea 11 dates = set(): Crea un conjunto vacío llamado dates para almacenar las fechas únicas encontradas en el archivo de registro de correo.

De la lineas 12-20: Este bucle for itera a través de cada línea en log_data: - Busca una coincidencia de fecha utilizando date_pattern y agrega la fecha al conjunto dates. - Busca una coincidencia de evento utilizando event_pattern, convierte el evento a minúsculas y actualiza el conteo en el diccionario events.

21-22: Encuentra las fechas mínima y máxima en el conjunto dates.

23-24: Convierte las fechas mínima y máxima a objetos datetime.

Linea 25: Calcula el número de días entre las fechas mínima y máxima.

26-27. Define los formatos de cadena para la salida en la tabla.

28-32. Define las traducciones para los eventos y convierte la primera letra a mayúscula.

33-34. Imprime el encabezado y el rango de fechas de la tabla.

35-41. Itera a través de los eventos y calcula los promedios diarios, semanales, mensuales y anuales. Luego, imprime la tabla con los resultados.

En caso de error de SyntaxError: Non-ASCII character in file

El error se debe a que los caracteres no ASCII están presentes en el script, y Python 2 requiere una declaración de codificación para esos caracteres.

Solución
Para solucionar este problema, simplemente añade la siguiente línea al comienzo del archivo:
# -*- coding: utf-8 -*-
import re 
from collections import defaultdict, OrderedDict 
from datetime import datetime, timedelta
Nota actualizado:
Para facilitar la ejecución puedes agregar como primeras lineas en la cabecera
#!/usr/bin/env python
# -*- coding: utf-8 -*-

La primera linea le indicamos que utilice el interprete de Python por defecto en el script, lo anterior es porque en Linux podemos tener instalada diferentes versiones de phyton, igual pudiéramos indicarle una especifica por ejemplo #!/usr/bin/python3.5, aunque este script esta optimizado para que trabaje con la version 2.5

Igualmente, una vez terminado el script o programa en python, se le debe otorgar los permisos de ejecución para que puedas ejecutarlo en el sistema:

chmod +x script_estadístico_log_postfix.py

Ahora solo debe ejecutarlo con

./script_estadístico_log_postfix.py

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *