The post Análizando logs de IIS con Pandas appeared first on S3lab.
]]>Empezemos el análisis.
%pylab inline Populating the interactive namespace from numpy and matplotlib
Indicamos la ruta la fichero de log.
log_path = r'./log'
Añadimos los imports necesarios. En concreto utilizamos las librerías de numpy y pandas, del sistema operativo; matplotlib para poder obtener gráficas y finalmente, seaborn, que mejora el aspecto visual de matplotlib.
import pandas as pd import numpy as np import os import matplotlib.pyplot as plt import seaborn
Leemos todos los ficheros de log, y todas las entradas, eliminando todas aquellas que sean comentarios.
def parse_logs(path): logs = [] for file in os.listdir(path): if file.endswith(".log"): # First, we read all the lines of the file, excluding the coments file = [x.split(' ') for x in open(path + '/' + file).readlines() if x[0] is not '#'] # We append the files logs += file return logs logs = parse_logs(log_path)
Cargamos el fichero en un DataFrame de Pandas
df = pd.DataFrame(logs)
Cambiamos el nombre de las columnas para que sea más legible
df.columns = ['date', 'time', 's-ip', 'cs-method', 'cs-uri-stem', 'cs-uri-query', 's-port', 'cs-username', 'c-ip', 'cs(User-Agent)', 'sc-status', 'sc-substatus', 'sc-win32-status', 'time-taken']
Ahora, convertimos combinamos la fecha y la hora, y lo sustituimos en el dataFrame.
df.insert(0, 'datetime', pd.to_datetime(df.apply(lambda x: x['date'] + ' ' + x['time'], 1))) df = df.drop(['date', 'time'], 1) # Creamos un índice con el tiempo df.index = df['datetime'] df.drop('datetime',1)
s-ip | cs-method | cs-uri-stem | cs-uri-query | s-port | cs-username | c-ip | cs(User-Agent) | sc-status | sc-substatus | sc-win32-status | time-taken | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
datetime | ||||||||||||
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/RemoteRecorder.svc | – | 80 | – | 152.3.113.150 | – | 200 | 0 | 0 | 78\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/RemoteRecorder.svc | – | 80 | – | 152.3.137.194 | – | 200 | 0 | 0 | 31\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/UploadTracker.svc | – | 80 | – | 152.3.102.77 | – | 200 | 0 | 0 | 15\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/Recorder.asmx | – | 80 | 00000004:win.duke.edu\jlv11 | 152.3.41.226 | Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Serv… | 200 | 0 | 0 | 437\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/Recorder.asmx | – | 80 | 00000005:avws2 | 152.3.161.68 | Mozilla/4.0+(compatible;+MSIE+6.0;+MS+Web+Serv… | 200 | 0 | 0 | 234\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/RemoteRecorder.svc | – | 80 | – | 152.3.157.149 | – | 200 | 0 | 0 | 46\n |
2012-03-01 00:00:00 | 152.3.102.77 | POST | /Panopto/Services/RemoteRecorder.svc | – | 80 | – | 152.3.113.150 | – | 200 | 0 | 0 | 265\n |
Y vemos de un primer vistazo los datos.
df.describe()
datetime | s-ip | cs-method | cs-uri-stem | cs-uri-query | s-port | cs-username | c-ip | cs(User-Agent) | sc-status | sc-substatus | sc-win32-status | time-taken | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 | 22404 |
unique | 706 | 1 | 3 | 387 | 281 | 2 | 15 | 147 | 23 | 6 | 1 | 2 | 141 |
top | 2012-03-01 00:11:05 | 152.3.102.77 | POST | /Panopto/Services/RemoteRecorder.svc | – | 80 | – | 152.3.41.226 | – | 200 | 0 | 0 | 15\n |
freq | 128 | 22404 | 21493 | 9325 | 22085 | 22379 | 21589 | 5122 | 20917 | 17852 | 22404 | 22387 | 4554 |
first | 2012-03-01 00:00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
last | 2012-03-01 00:12:08 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
En primer lugar, vamos a analizar la frecuencia con la que el serividor recibe peticiones.
# Nos quedamos con la columna de tiempo datetimeDF = df.ix[0:, ['datetime']] server_times = [] for i, row in datetimeDF.iterrows(): server_times.append(row['datetime']) # Y ordenamos la lista server_times.sort() time_until_next = [] for i in xrange(1, len(server_times) - 1): time_diff = (server_times[i] - server_times[i-1]).seconds time_until_next.append(time_diff)
time_to_next_series = pd.Series(time_until_next) time_to_next_series.hist(normed=True)
<matplotlib.axes._subplots.AxesSubplot at 0x97bcb00>
A continuación, analizamos la información de las IPs desde las que se conectan.
Para ello, primero agrupamos las IPs y calculamos cuantas peticiones hay de cada IP.
ip = df.groupby('c-ip').size()
Analicemos ahora las 10 que más visitan.
ip.sort() ip[-10:].plot(kind='barh')
<matplotlib.axes._subplots.AxesSubplot at 0x78abac8>
A continuación se obtienen datos de los distintos tipos de respuestas posibles. Creamos un DataFrame para cada uno de los tipos de error que contemplamos. También vamos a hacer un resample, con una frecuencia de «5t», es decir, por cada 5 muestras de tiempo t se genera una.
# Convertimos la columna a columna de ints df['sc-status'] = df['sc-status'].astype(int) t_span = '5t' df_404 = df['sc-status'][df['sc-status'] == 404].resample(t_span, how='count') df_403 = df['sc-status'][df['sc-status'] == 403].resample(t_span, how='count') df_301 = df['sc-status'][df['sc-status'] == 301].resample(t_span, how='count') df_302 = df['sc-status'][df['sc-status'] == 302].resample(t_span, how='count') df_304 = df['sc-status'][df['sc-status'] == 304].resample(t_span, how='count') df_200 = df['sc-status'][df['sc-status'] == 200].resample(t_span, how='count') status_df = pd.DataFrame({'Not Found':df_404, 'Forbidden':df_403, 'Moved Permanently':df_301, 'Moved Temporaly': df_302, 'Not Modified':df_304, 'OK':df_200}) status_df
Forbidden | Moved Permanently | Moved Temporaly | Not Found | Not Modified | OK | |
---|---|---|---|---|---|---|
datetime | ||||||
2012-03-01 00:00:00 | NaN | 63 | 108 | NaN | 11 | 7492 |
2012-03-01 00:05:00 | NaN | NaN | 98 | NaN | 24 | 7115 |
2012-03-01 00:10:00 | NaN | NaN | 2 | NaN | NaN | 3245 |
Normalizamos los datos a 1 para ver el gráfico de forma más clara
normed_subset = status_df[['OK','Moved Temporaly']].div(status_df[['OK','Moved Temporaly']].sum(1), axis = 0) normed_subset.plot(kind='barh', stacked=True)
<matplotlib.axes._subplots.AxesSubplot at 0xc284a58>
Esto es sólo un pequeño ejemplo de las cosas que se pueden hacer con este tipo de herramientas.
Ahora os toca a vosotros jugar con vuestros logs y empezar a analizarlos.
The post Análizando logs de IIS con Pandas appeared first on S3lab.
]]>