Официальная возможность получить лицензионный софт бесплатно.
Giveaway of the Day
Это не реклама!

Щелкните для получения прогноза по Биробиджану


пятница, 26 мая 2017 г.

SQUID, AWK и статистика

Итак, выяснилось, что какой-то специфичный анализатор лога, чтобы собирать ежедневную обобщенную статистику, мне не требуется.

Что нужно? Нужно посчитать, сколько всего трафика за сутки израсходовал тот или иной пользователь.

Решаем задачу наличными силами и подручными средствами. Лог сквида имеет вполне определенный формат, гугл в помощь. Мне нужны поля: передано байт (5), имя пользователя (8) и результат запроса (4). Ну и воспользуемся такой прелестью авка, как ассоциативные массивы. Дальше - просто копипаста рабочего скрипта.
MAWK давно не обновлялся, поэтому я явно указал интерпретатор GAWK.

#!/usr/bin/gawk -f
# usage:
# 1) get_sqlog.awk filename
# 2) cat filename|get_sqlog.awk

# Если нет пользователя или есть один из двух отлупов, то переходим к следующей строке
{if ($8 == "-" || $4 == "TCP_DENIED/407" || $4 == "TCP_DENIED/403") { next }
# Ассоциативные массивы, в качестве индекса - имя пользователя
# Сколько раз он нам попался
    ++occurrences[$8]
# Его трафик
    summary[$8]=summary[$8]+$5
}
END {
# Проходим по всем элементам массива и красиво печатаем их
# Переменная а принимает значения индексов, определенные во время анализа
for (a in occurences){
    printf "%-30s:%10d:%10d\n",a,occurrences[a],summary[a]
    }
}

Под катом подробное описание.



Всё, что не входит в разделы BEGIN и END, выполняется для каждой строки входного файла. Соответственно, для каждой строки будет выполнена проверка: есть ли в ней имя пользователя (если его нет, то сквид ставит "прочерк" - дефис), и была ли операция успешна. Если хотя бы одно из условий ( || ) не выполняется, то прекращаем обработку этой строки и переходим к следующей ( next ).

Если же содержимое строки нас устраивает, то, как я уже сказал, будем пользоваться ассоциативными массивами AWK-a. Не надо только их путать с украинской евроотсосиацией - слова похожие, а вот смысл...

Что есть ассоциативный массив (АсМ)? Это массив, в котором и значения элементов и их индексы хранятся вместе. У классического массива хранятся только данные фиксированного размера, а индексы - просто числа, обозначающие смещение от начала участка памяти, где оно хранится. У АсМ хранятся как значение, так и индекс. Поэтому в качестве индекса можно использовать что угодно - строку или число.

Вполне допустима конструкция (имена переменных условные) типа рецепт[название]="Вкуснотища"; рецепт[Выход готового продукта]=300; рецепт[5]="3 ст.л.". Надо также добавить, что массивы в AWK не требуют предварительного описания, и если элемент массива (переменная и индекс) впервые упоминается в  выражениях, то он автоматически создается. Подробнее см. мануал к гавку раздел 8.1.2. Этим я и воспользовался.

Данные из лога складываются в два массива:
occurrences: сколько раз пользователь попался в логе (аналогично: grep username logfile -c)
summary: общий объем трафика в строках с его именем.

Если пользователь попался впервые, то awk автоматически создаст соответствующие элементы массивов, поскольку именно имя пользователя использовано в качестве индекса. Что самое важное, что элементы массивов инициализируются при создании значением "" (пустая строка), что позволяет сразу начинать подсчёты. Если бы инициализация не выполнялась, то пришлось бы делать дополнительную проверку типа (внимание! в примере могут быть нарушения синтаксиса после "then", я его не проверял и привожу просто в качестве иллюстрации):

if ($8 in occurrences) then
    {++occurrences[$8]
    summary[$8]=summary[$8]+$5}
else
   {occurrences[$8]=1
   summary[$8]=$5}


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

 В итоге после обработки всех строк переданного файла в обоих массивах содержится одинаковое количество элементов, равное количеству уникальных имён пользователей, найденных в этом конкретном протоколе. А в самих элементах - нужные нам данные: количество обращений пользователя к прокси и трафик по ним. Может возникнуть вопрос: а где же имена пользователей? А они - см. выше про описание АсМ - хранятся где-то во внутренних структурах.

Остаётся только вывести куда-то результаты. Поскольку это - вывод результатов - одноразовая операция, то я разместил ее в разделе END. Вывод, что вполне логично, выполняется в цикле с обходом всех элементов упомянутых массивов. И на вопрос: "а как?" ответ следует из всё того же 8.1.2: используем штатную операцию проверки наличия заданного индекса среди индексов заданного массива. Ближе всего эта операция к известному оператору ForEach, который есть во многих языках и играет ту же самую роль - обход всех элементов какого-то массива. Конкретно в моем случае переменная "а" проходит по списку индексов обоих массивов (а эти списки совпадают) и при каждой итерации цикла печатается значение самой переменной (это и будет имя пользователя), а также индексированные этим именем элементы статистики из соответствующих массивов.

Параметры древней как мамонт команды printf я пояснять не буду, извините: они не меняются уже лет 40 или больше. Уточню лишь, что для моего собственного удобства текст выводится колонками фиксированной ширины, разделенными двоеточиями. Можно, допустим, сделать ширину столбцов переменной, взять поля в кавычки, а вместо двоеточий использовать точки с запятой, чтобы получилось что-то близкое к формату CSV.

Что дальше? А что угодно. Например, можно скормить вывод этого скрипта sendmail-у, какому-нибудь импортёру в какую-нибудь СУБД, полюбоваться глазками или просто игнорировать. Можно, допустим, обратиться в ADDS и по логину пользователя получить его настоящее имя, чтобы отчет выглядел красивше. Но мне очень нравится идеология в никсах: "тулза должна решать только одну задачу, но решать ее хорошо". Вот мой скрипт решает только одну задачу - преобразование лога в нужный формат. А использование результатов преобразования, это тема для отдельного разговора.

Комментариев нет:

Отправить комментарий

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