2012-09-22 27 views
24

Acabo de empezar a aprender Python y me gustaría leer un archivo de registro de Apache y poner partes de cada línea en listas diferentes.Analizando archivos de registro de apache

línea del archivo

172.16.0.3 - - [25/Sep/2002: 14: 04: 19 +0200] "GET/HTTP/1.1" 401 - "" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv: 1,1) Gecko/20020827"

según Apache website el formato es

% h% l% u% t \ "% r \ "%> s% b \"% {Referer} i \ "\"% {User-Agent} i \

Puedo abrir el archivo y simplemente leerlo tal como está, pero no sé cómo hacerlo leer en ese formato para poder poner cada parte en una lista.

+0

Qué elementos de esta línea está interesado? (¿Todos ellos?) –

+0

, ya que las líneas cambian ligeramente Me gustaría que se leyeran en ese formato exacto :) – ogward

+0

Usted entiende mal lo que quiero decir es, ¿qué quiere extraer de cada línea? ¿Las fechas? IP? ¿Todo ello? –

Respuesta

33

Este es un trabajo para regular expressions.

Por ejemplo:

line = '172.16.0.3 - - [25/Sep/2002:14:04:19 +0200] "GET/HTTP/1.1" 401 - "" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827"' 
regex = '([(\d\.)]+) - - \[(.*?)\] "(.*?)" (\d+) - "(.*?)" "(.*?)"' 

import re 
print re.match(regex, line).groups() 

la salida sería una tupla con 6 piezas de información de la línea (en concreto, los grupos dentro de paréntesis en ese patrón):

('172.16.0.3', '25/Sep/2002:14:04:19 +0200', 'GET/HTTP/1.1', '401', '', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827') 
+0

Esto se ve bien, pero ¿puedo de alguna manera tener un "regex" para cada parte? algo como esto 'ip = '([(\ d \.)] +)' date = '.........' req = '........... .'' – ogward

+0

Creo que lo descubrí. ¡Muchas gracias! – ogward

+1

Cuando intento alguna otra línea del archivo, no funciona. ex ** 127.0.0.1 - stefan [01/Apr/2002: 12: 17: 21 +0200] "GET /sit3-shine.7.gif HTTP/1.1" 200 15811 "http: // localhost /" "Mozilla/5.0 (compatible; Konqueror/2.2.2-2; Linux)" ** – ogward

12

Uso un habitual expresión para dividir una fila en "tokens" separados:

>>> row = """172.16.0.3 - - [25/Sep/2002:14:04:19 +0200] "GET/HTTP/1.1" 401 - "" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827" """ 
>>> import re 
>>> map(''.join, re.findall(r'\"(.*?)\"|\[(.*?)\]|(\S+)', row)) 
['172.16.0.3', '-', '-', '25/Sep/2002:14:04:19 +0200', 'GET/HTTP/1.1', '401', '-', '', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827'] 

Otra solución es t o use una herramienta dedicada, p. http://pypi.python.org/pypi/pylogsparser/0.4

9

He creado una biblioteca de Python que hace exactamente eso: apache-log-parser.

>>> import apache_log_parser 
>>> line_parser = apache_log_parser.make_parser("%h <<%P>> %t %Dus \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %l %u") 
>>> log_line_data = line_parser('127.0.0.1 <<6113>> [16/Aug/2013:15:45:34 +0000] 1966093us "GET/HTTP/1.1" 200 3478 "https://example.com/" "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18)" - -') 
>>> pprint(log_line_data) 
{'pid': '6113', 
'remote_host': '127.0.0.1', 
'remote_logname': '-', 
'remote_user': '', 
'request_first_line': 'GET/HTTP/1.1', 
'request_header_referer': 'https://example.com/', 
'request_header_user_agent': 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18)', 
'response_bytes_clf': '3478', 
'status': '200', 
'time_received': '[16/Aug/2013:15:45:34 +0000]', 
'time_us': '1966093'} 
7

RegEx parecía extrema y problemático teniendo en cuenta la simplicidad del formato, así que escribí este pequeño divisor, que otros pueden encontrar útil, así:

def apache2_logrow(s): 
    ''' Fast split on Apache2 log lines 

    http://httpd.apache.org/docs/trunk/logs.html 
    ''' 
    row = [ ] 
    qe = qp = None # quote end character (qe) and quote parts (qp) 
    for s in s.replace('\r','').replace('\n','').split(' '): 
     if qp: 
      qp.append(s) 
     elif '' == s: # blanks 
      row.append('') 
     elif '"' == s[0]: # begin " quote " 
      qp = [ s ] 
      qe = '"' 
     elif '[' == s[0]: # begin [ quote ] 
      qp = [ s ] 
      qe = ']' 
     else: 
      row.append(s) 

     l = len(s) 
     if l and qe == s[-1]: # end quote 
      if l == 1 or s[-2] != '\\': # don't end on escaped quotes 
       row.append(' '.join(qp)[1:-1].replace('\\'+qe, qe)) 
       qp = qe = None 
    return row 
+0

Esto funcionó para mí con Python 3. Recibía errores con el otro ejemplos de expresiones regulares. Gracias. –

1

Añadir esta en httpd.conf para convertir el apache registros a json.

LogFormat "{\"time\":\"%t\", \"remoteIP\" :\"%a\", \"host\": \"%V\", \"request_id\": \"%L\", \"request\":\"%U\", \"query\" : \"%q\", \"method\":\"%m\", \"status\":\"%>s\", \"userAgent\":\"%{User-agent}i\", \"referer\":\"%{Referer}i\" }" json_log 

CustomLog /var/log/apache_access_log json_log 
CustomLog "|/usr/bin/python -u apacheLogHandler.py" json_log 

Ahora ves que access_logs en formato json. Utilice el siguiente código python para analizar los registros json que se actualizan constantemente.

apacheLogHandler.py

import time 
f = open('apache_access_log.log', 'r') 
for line in f: # read all lines already in the file 
    print line.strip() 

# keep waiting forever for more lines. 
while True: 
    line = f.readline() # just read more 
    if line: # if you got something... 
    print 'got data:', line.strip() 
    time.sleep(1) 
0
import re 


HOST = r'^(?P<host>.*?)' 
SPACE = r'\s' 
IDENTITY = r'\S+' 
USER = r'\S+' 
TIME = r'(?P<time>\[.*?\])' 
REQUEST = r'\"(?P<request>.*?)\"' 
STATUS = r'(?P<status>\d{3})' 
SIZE = r'(?P<size>\S+)' 

REGEX = HOST+SPACE+IDENTITY+SPACE+USER+SPACE+TIME+SPACE+REQUEST+SPACE+STATUS+SPACE+SIZE+SPACE 

def parser(log_line): 
    match = re.search(REGEX,log_line) 
    return ((match.group('host'), 
      match.group('time'), 
         match.group('request') , 
         match.group('status') , 
         match.group('size') 
        ) 
        ) 


logLine = """180.76.15.30 - - [24/Mar/2017:19:37:57 +0000] "GET /shop/page/32/?count=15&orderby=title&add_to_wishlist=4846 HTTP/1.1" 404 10202 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)""" 
result = parser(logLine) 
print(result) 
Cuestiones relacionadas