- отсортировать IP адреса по количеству запросов, где статус код 200, подсчитать количество запросов с каждого из IP адресов
cat access.log | head -n 2
13:55:30 187.233.224.30 https://samplesite.com/cghcfgcecb.php 404
13:55:31 216.8.199.224 https://samplesite.com/cfaddbedhh.php 302
Чтобы получить вывод такого формата (отсортированный по количеству:
IP адрес, количество запросов с ответом 200
Вот всё норм, как грамотно парсить табуляцию (\t) ? Или может у кого-то есть готовое решение?
Да хоть как ксв
Можно даже пандасом прочитать
Переформулирую вопрос: есть файл со стороками: 13:55:30 187.233.224.30 https://samplesite.com/cghcfgcecb.php 404 В строке 4 поля - time, IP, URL, status, разделенные табуляцией \t Нужно проверить 4 столбец на наличие значения "200" Как это красиво сделать? Если просто по строке искать, то в поле url тоже может быть значение 200, например https://samplesite.com/chafsidjhfosidf.php?param=200
Распарсить файл в список dict/объектов, а затем сравнивать у каждого элемента поле с нужным тебе значением
файл огромный и динамический, не вызовет ли это проблем? (поэтому работаю с конкретной строкой)
Что значит динамический
значит старые строки удаляются, но появляются новые (ротация лога)
можно построчно через .split(' ') потом из полученного массива 4й элемент проверяй на 200
вот да. точно. спасибо
С постоянно обновляемым файлом все не так просто
Можешь сплитать по табу
Оно понятно, но под текущую задачу подходит вариант с работой с конкретной строкой на момент открытия файла. Тут другая проблема сейчас. Я парсю строку в список, и всё работает. То есть я могу вывести строку как список после сплита. Всё хорошо тут. ['14:18:29', '88.7.61.66', 'https://samplesite.com/ahdffgcffh.php', '200\n'] или выводить только 4 столбец - тоже всё ок. Но когда я пытаюсь сделать так: if log_line[3] == 200: то всегда возвращается false. пробовал еще так (на всякий случай) if str(log_line[3]) == "200":
Ты перевод строки в видишь? И то, что сравниваешь строку с числом?
увидел. спасибо :) То есть, у меня сраванивалось 200\n с 200
Ты хочешь сделать мониторинг на основе логов. Это дичь, так делать не нужно
это тестовое задание :) Так-то я под анализ логов использую логстеш эластик и кибану :) + задание я реализовал на баше в 2 строки c использованием awk sort uniq А вот на Python с ходу не получается уже
На какую позицию тестовое?
AppSec Engineer однострочник на баше выглядит так: awk '$4 == "200"' access.log | awk '{print $2}' | sort | uniq -c | sort -nr | head -n 10 Теперь надо это реализовать на Python :)
os.system("awk '$4 == "200"' access.log | awk '{print $2}' | sort | uniq -c | sort -nr | head -n 10") не благодари
Реализуй через subprocess)))
да, это план Б :)))
Можно потом в любом случае сразу две версии отправить )))
with Path("path_to_your_log_file").open("r") as f: lines = f.readlines() lines_with_200 = list(filter(lambda o: int(o.split(" ")[3]) == 200, lines)) можно вместо лямбды нормальную функцию с проверками что есть сплит, есть 4й элемент и есть конвертация в инт
Ну основная часть есть(всё проверяется), сейчас осталось подсчитать IP адреса, с которых были 200, отсортировать IP по количеству запросов с 200 ответом и вывести топ10 :)
set([1, 2, 1]) >>> {1, 2} sorted([5, 1, 4]) >>> [1, 4, 5] Если надо отсортировать + уникальные list(sorted(set([1, 5, 5, 4])))
на примере выглядит очень просто. :)
sorted возвращает список, второй раз не нада в него загонять
sorted() и так возвращает список, list() уже не нужно добавлять
Рил, ошибся, спасибо
from collections import Counter with Path("ttt.txt").open("r") as f: lines = f.readlines() lines_with_200 = Counter(list(filter(lambda o: int(o.split(" ")[3]) == 200, lines))).most_common() print("\n".join([f"Count: {v}, URL: {k.strip()}" for k, v in lines_with_200][:10]))
Может хотя бы моноширинным?
int(o.split(" ")[3]) == 200 Я б не делал А если там не число?
вы сообщение до конца дочитали? "можно вместо лямбды нормальную функцию с проверками что есть сплит, есть 4й элемент и есть конвертация в инт"
Сплит делай и проверяй
Обсуждают сегодня