Analizar logs de IIS con PowerShell
Existen numerosas herramientas de análisis de logs para IIS y para logs en general, y probablemente sea una excelente idea utilizar estos sistemas para realizar un monitoreo continuo de nuestras soluciones. Sin embargo, en el mundo real a veces solo tienes un montón de logs de IIS y algunas preguntas simples por responder con la información que allí se aloja.
PowerShell viene integrado al Sistema Operativo, por lo que pasa a ser LA OPCIÓN predeterminada para este tipo de escenarios.
Recursos a disposición
El formato de los logs de IIS es W3C Extended y, básicamente, la estructura de los logs es la siguiente:
Adicional a lo anterior el formato no se encuentra muy alineado con los comandos incorporados de PowerShell, por ejemplo los cmdlets Import-Csv o ConvertFrom-Csv. Si bien pueden ser utilizados con el parámetro Delimeter y algunas manipulaciones de los headers, no es el mejor recurso disponible. Si comenzamos a pensar en manipulación del contenido, lo primero que debemos considerar son las expresiones regulares.
Hace un tiempo escribí una entrada en este blog sobre el tema expresiones regulares en PowerShell.
Código
De lo que se expuso anteriormente, podríamos resolver nuestro problema con el siguiente bloque de código:
Obteniendo la siguiente salida en consola:
Paso a paso
Ahora vamos a desglosar cada línea para entender mejor que ejecutamos :)
Lo primero, se define una variable donde vamos a definir el archivo a analizar (después vamos a mejorar este mecanismo) junto a un array donde se guardarán los valores del log ya manipulado.
Por medio del cmdlet Get-Content obtenemos la información del log y utilizamos Foreach-Object para analizar cada línea del archivo.
El primer if comprueba si la línea de texto comienza con el caracter # (por medio de una expresión regular muy sencilla): esto se debe a que al momento de comenzar a registrar los eventos y actividades, el sistema agrega líneas de información (sistema utilizado, fecha, formato del log):
Y éstas deben ser descartadas… Pero antes debemos considerar un segundo if en donde se utiliza una expresión regular un poco más compleja para separar en 2 grupos los valores y así poder filtrar lo que realmente es necesario. La expresión regular en cuestión es la siguiente:
^#(?<Clave>[^:]+):\s+(?<Valor>.+)$
Les comparto un recurso web para realizar comprobaciones de expresiones regulares: https://regex101.com/. Si tomamos el bloque de texto anterior la comprobación del patrón definido cumple con lo que requerimos:
Y en caso que corresponda a una línea con información de actividad en el servidor, la misma es separada por cada propiedad y agregada al objeto custom [pscustomobject]$Properties.
Mejoras
Siempre es posible mejorar código… para ello es posible agrupar el bloque anterior bajo una función, como por ejemplo:
Y usar la función de la siguiente manera:
Happy scripting!
Comments