Подсчет байтов, переданных из журналов HTTP - PullRequest
0 голосов
/ 01 марта 2020

Я новичок в python и мне нужно проанализировать коды состояния. У меня есть задача разобрать файл журнала HTTP:

  • Группировать зарегистрированные запросы по IP-адресу или коду статуса HTTP (выбирается пользователем).
  • Рассчитать одно из следующего ( выбирается пользователем) для каждой группы:
    1. Количество запросов
    2. Процент количества запросов ко всем зарегистрированным запросам
    3. Общее количество переданных байтов.

Я сделал подсчет запросов и процентов. Теперь я не знаю, как считать переданные байты (3-я задача).

Пример файла журнала (здесь показаны байты после кода состояния: 6146, 52315, 12251, 54662):

93.114.45.13 - - [17/May/2015:10:05:17 +0000] "GET /images/jordan-80.png HTTP/1.1" 200 6146 "http://www.semicomplete.com/articles/dynamic-dns-with-dhcp/" "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
93.114.45.13 - - [17/May/2015:10:05:21 +0000] "GET /images/web/2009/banner.png HTTP/1.1" 200 52315 "http://www.semicomplete.com/style2.css" "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
66.249.73.135 - - [17/May/2015:10:05:40 +0000] "GET /blog/tags/ipv6 HTTP/1.1" 200 12251 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; Googlebot/2.1;
+http://www.google.com/bot.html)"83.149.9.216 - - [17/May/2015:10:05:25 +0000] "GET /presentations/logstash-monitorama-2013/images/elasticsearch.png HTTP/1.1" 200 8026 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
83.149.9.216 - - [17/May/2015:10:05:59 +0000] "GET /presentations/logstash-monitorama-2013/images/logstashbook.png HTTP/1.1" 200 54662 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"

Мой код:

import re
import sys
from collections import Counter

def getBytes(filename):
    with open(filename, 'r') as logfile:
        for line in logfile:
            newlist=line.split(" ")    
            print(newlist[0]+" "+newlist[9])

def countIp(filename):
    print ("hey")
    myregex = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    with open(filename) as f:
        log = f.read()
        my_iplist = re.findall(myregex,log)
        ipcount = Counter(my_iplist)
        s = sum(ipcount.values())
        for k,v in ipcount.items():        
            pct = v * 100.0 / s   
            print("IP Address " + "=> " + str(k) + " " + "Count "  + "=> " + str(v) + " Percentage " +"=> "+ str(pct) +"%")

def countStatusCode(filename):
    print ("hey")
    myregex = r'\b[2-5]\d\d\s'
    with open(filename) as f:
        log = f.read()
        my_iplist = re.findall(myregex,log)
        ipcount = Counter(my_iplist)
        s = sum(ipcount.values())
        for k,v in ipcount.items():        
            pct = v * 100.0 / s   
            print("IP Address " + "=> " + str(k) + " " + "Count "  + "=> " + str(v) + " Percentage " +"=> "+ str(pct) +"%")

if __name__ == '__main__':   
    filename=sys.argv[1]
    val = input("Enter your choice (ip or status code): ") 
    if val in ["ip","IP","Ip","iP"]:    
        countIp(filename)
    elif val in ["statusCode","code","sc","Status Code","status"]:
        countStatusCode(filename)

Ответы [ 2 ]

0 голосов
/ 01 марта 2020

Вместо того чтобы использовать несколько регулярных выражений, делающих несколько проходов через журнал, это решение использует одно регулярное выражение для извлечения всех соответствующих значений за один проход.

Функция process_log передает текст журнала как одна строка. В следующей демонстрационной программе используется тестовая строка. Реальная реализация будет вызывать эту функцию с результатами чтения фактического файла журнала.

Чтобы отслеживать IP-адреса / пары состояний, используется defaultdict с использованием list в качестве default_factory. Количество элементов в списке подсчитывает количество раз, когда комбинация IP-адрес / статус была замечена, и каждый элемент списка - это количество байтов, переданных для этого HTTP-запроса. Например, пара ключ / значение из словаря ip_status может быть:

key: ('123.12.11.9', '200')  value: [6213, 9876, 376]

Интерпретация вышесказанного состоит в том, что для IP-адреса было 3 экземпляра кода состояния «200» 123.12.11.9 'открыл. Передано 3 байта для этих 3 экземпляров: 6213, 9876 и 376.

Объяснение регулярного выражения:

(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - .*?HTTP/1.1" (\d+) (\d+)
  1. (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - По сути, это регулярное выражение, используемое OP для распознать IP-адрес, поэтому он не требует большого объяснения. Я добавил за ним - -, чтобы обеспечить дополнительный следующий контекст на случай, если есть другие примеры похожих строк. IP-адрес фиксируется в группе захвата 1.
  2. .*? Это будет соответствовать не жадно 0 или более символов без перевода строки до следующего.
  3. HTTP/1.1" Соответствует строке HTTP/1.1" чтобы предоставить левый контекст для следующего.
  4. (\d+) Соответствует одному или нескольким di git в Capture Group 2 (статус).
  5. Соответствует одному пробелу .
  6. (\d+) Соответствует одному или нескольким ди git в группе захвата 3 (переданные байты).

См. Демонстрационный пример Regex

Другими словами, я просто хочу убедиться, что я подбираю правильные поля из правильного места, сопоставляя то, что я ожидаю найти next с полями, которые я ищу. Когда ваше регулярное выражение возвращает несколько групп, finditer часто более удобно, чем findall. finditer возвращает итератор, выдающий объект соответствия для каждой итерации. Я добавил код для получения статистики для и ip / код состояния / переданных байтов и просто код состояния . Вам нужно только одно или другое в зависимости от того, что хочет пользователь.

Код:

import re
from collections import defaultdict

def process_log(log):
    ip_counter = defaultdict(list)
    status_counter = defaultdict(int)
    total_count = 0
    for m in re.finditer(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - .*?HTTP/1.1" (\d+) (\d+)', log):
        total_count += 1
        ip = m[1]
        status = m[2]
        bytes = int(m[3])
        ip_counter[(ip, status)].append(bytes)
        status_counter[status] += 1
    for k, v in ip_counter.items():
        count = len(v)
        percentage = count/total_count
        total_bytes = sum(v)
        ip = k[0]
        status = k[1]
        print(f"IP Address => {ip}, status => {status}, Count => {count}, Percentage => {percentage}, Total Bytes Transferred => {total_bytes}")
    for k, v in status_counter.items():
        count = v
        percentage = count/total_count
        print(f"Status Code => {k}, Percentage => {percentage}")




log = """93.114.45.13 - - [17/May/2015:10:05:17 +0000] "GET /images/jordan-80.png HTTP/1.1" 200 6146 "http://www.semicomplete.com/articles/dynamic-dns-with-dhcp/" "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
93.114.45.13 - - [17/May/2015:10:05:21 +0000] "GET /images/web/2009/banner.png HTTP/1.1" 200 52315 "http://www.semicomplete.com/style2.css" "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
66.249.73.135 - - [17/May/2015:10:05:40 +0000] "GET /blog/tags/ipv6 HTTP/1.1" 200 12251 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; Googlebot/2.1;
+http://www.google.com/bot.html)"83.149.9.216 - - [17/May/2015:10:05:25 +0000] "GET /presentations/logstash-monitorama-2013/images/elasticsearch.png HTTP/1.1" 200 8026 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
83.149.9.216 - - [17/May/2015:10:05:59 +0000] "GET /presentations/logstash-monitorama-2013/images/logstashbook.png HTTP/1.1" 200 54662 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"
"""

process_log(log)

Отпечатки:

IP Address => 93.114.45.13, status => 200, Count => 2, Percentage => 0.4, Total Bytes Transferred => 58461
IP Address => 66.249.73.135, status => 200, Count => 1, Percentage => 0.2, Total Bytes Transferred => 12251
IP Address => 83.149.9.216, status => 200, Count => 2, Percentage => 0.4, Total Bytes Transferred => 62688
Status Code => 200, Percentage => 1.0

См. Python Демо

0 голосов
/ 01 марта 2020

Чтобы получить количество байтов, переданных из вашего лог-файла:

def getBytes(filename):
    with open(filename, 'r') as logfile:
        for line in logfile:
            regex = r'\/.+?\sHTTP\/1\..\"\s.{3}\s(.+?)\s'
            bytesCount = re.search(regex, line)[1]
            print("Bytes transfered: "+bytesCount)
...