Всем привет! Снова на связи Алексей Холодаев из Cloud4Y.
Возникла у меня необходимость мониторить исходящий и входящий трафик на личном облачном хранилище Nextcloud. О том, как я решал эту задачу и какие трудности возникли в процессе, сегодня и рассскажу.
Что такое Nextcloud, знают, наверное, многие читатели. Поэтому ограничусь небольшим определением: Nextcloud — это программный комплекс, который реализует облачное хранилище данных. Удобная штука, по правде говоря.
Мониторинг трафика был нужен для обнаружения наиболее популярных файлов, которые скачивают и загружают пользователи, а также сбора данных о размере этих файлов. Статистика, все дела.
Какие данные о трафике я хотел собирать:
Тип операции (скачивание файла с хранилища или загрузка в хранилище Nextcloud).
Полное расположение файла, с которым что-то делали.
Имена пользователей, которые производили данные операции.
Дата и время выполнения операций.
Размер скачанных и загруженных файлов.
Поясню первый пункт. Типы операций «скачивание с Nextcloud» и «загрузка на Nextcloud» обладают подтипами: напрямую через web-интерфейс, через общие локальные ссылки (Internal link share), через общие публичные ссылки (Public link share). Мне нужно было учитывать все подтипы этих операций. Мониторинг осуществлялся локально на одном сервере с Nextcloud, а не на внешних сервисах.
В ходе решения этой задачи я не нашёл встроенных инструментов и плагинов для Nextcloud. Но поиск привёл меня к административной базе данных Nextcloud, которая представляла собой базу данных на PostgreSQL. Эта БД хранила в своих таблицах информацию об активностях пользователей. В том числе об исходящем и входящем трафике. Что я нашёл в ней:
Тип операции (скачивание файлов с хранилища Nextcloud через общие публичные ссылки, либо локальные ссылки или загрузка файлов на хранилище Nextcloud).
Размер файлов, над которыми производились операции (скачивание, загрузка, etc).
Пользователи, которые совершали эти операции.
Дата и время выполнения этих операций.
Казалось бы, всё. Я близок к решению своей задачи и могу брать всю нужную мне информацию из этой БД. Но увы, в ней не было данных по операциям скачивания непосредственно через web-интерфейс Nextcloud, что меня не устраивало.
Ещё один ресёрч дал мне информацию о том, что вся нужная информация есть в логе Nextcloud по пути /var/log/nextcloud/audit.log
. Но в этом логе не указывался размер загруженных и скачанных файлов. Сам audit.log имеет определённый формат. Опять трудность.
Впрочем, почему бы не попытаться брать информацию из audit.log, а размер файлов искать в административной БД Nextcloud на PostgreSQL по информации, взятой из этого лога? Затем всю информацию складывать в другую базу данных на MySQL. И уже из базы данных MySQL делать выборки и осуществлять мониторинг исходящего и входящего трафика.
Так как необходимо было работать с текстом, я взял на вооружение очень хорошую утилиту для работы с ним: AWK. Она использует язык AWK: C-подобный скриптовый язык построчного разбора и обработки входного потока (например, текстового файла) по заданным шаблонам (регулярным выражениям). Может использоваться в сценариях командной строки. Как любой другой язык, AWK обладает синтаксисом. Команды утилиты AWK обладают тем же синтаксисом. Он приведён ниже:
awk опции 'условие {действие}'
Если вы хотите сделать не одно действие, а последовательность действий:
awk опции 'условие {действие} условие {действие}'
Второй вариант я не применял в своём скрипте, он просто для ознакомления.
Перечислю некоторые опции
-F, --field-separator — позволяет задать какой-то конкретный разделитель в виде символа либо строки символов через регулярные выражения;
-f, --file — позволяет прочитать данные не из стандартного вывода, а из файла;
-v, --assign — позволяет присвоить значение переменной, которая будет использоваться в AWK;
-b, --characters-as-bytes — считать все символы однобайтовыми;
-d, --dump-variables — вывести значения всех переменных AWK по умолчанию;
-D, --debug — режим отладки, позволяет вводить команды интерактивно с клавиатуры;
-e, --source — выполнить указанный код на языке AWK;
-o, --pretty-print — вывести результат работы программы в файл;
-V, --version — вывести версию утилиты.
Из этих опций я использовал только -F для задания разделителя и –v для присвоения значения переменной в утилите AWK.
Приведу также несколько функций-действий и их краткое описание:
print(строка) — вывод чего либо в стандартный поток вывода;
printf(строка) — форматированный вывод в стандартный поток вывода;
system(команда) — выполняет команду в системе;
length(строка) — возвращает длину строки;
substr(строка, старт, количество) — обрезает строку и возвращает результат;
tolower(строка) — переводит строку в нижний регистр;
toupper(строка) — переводить строку в верхний регистр.
Из этих функций я использовал в своём скрипте только две, print(строка) и system(команда). Также использовал некоторые операторы и переменные в функциях-действиях:
NR - общее количество строк в обрабатываемом тексте;
$ - ссылка на колонку по номеру.
Конечно, на самом деле их гораздо больше, чем я смог перечислить.
В скрипте использовал условия для обработки только тех строк, которые удовлетворяют этому условию. А ещё хотелось максимально быстро обработать текст в скрипте, без лишних операций записи на диск и чтения с диска.
Некоторая логика работы скрипта стала понятна и я реализовал решение в виде двух скриптов на языке Bash и одного текстового файла start_point.txt для записи в него номера последней обработанной строки. Это позволяло при следующей проверке начать с неё, а не с самого начала. Скрипт планировал запускать по расписанию через cron.
Первый скрипт с именем rassparsiv_audit_log.sh вытаскивает нужную информацию из лог-файла Nextcloud audit.log, запуская для каждой строки скрипт insert_into.sh , который ищет информацию в административной БД Nextcloud на PostgreSQL и складывает всё найденное во вторую БД на MySQL.
Расскажу о скрипте rassparsiv_audit_log.sh, приведя его полное содержание:
Num=$(cat start_point.txt | tail -n1)
cat /var/log/nextcloud/audit.log | awk -v k=$Num -F"," 'NR > k''{print $3,$4,$5 ,$9}' | awk -v m='"' -F'"' '{print " ","|"," ",m,$4,m," ","|"," ",m,$8,m," ","|"," ",m,$12,m," ","|"," "m,$16,m," ","|"," ",m,$17,m," ","|"," "}' | awk -F' \\| ' '{system("./insert_into.sh " $2 " " $3 " " $4 " " $5 " " $6)}'
cat /var/log/nextcloud/audit.log | wc -l >> start_point.txt
Разберём его построчно
Первая строчка скрипта говорит записать номер последней строки, которая была обработана в прошлый раз, из текстового файла start_point в переменную Num, для последующего начала обработки с этой строки:
Num=$(cat start_point.txt | tail -n1)
Далее написан пайплайн, который собирает построчно информацию о трафике из лога audit.log Nextcloud и запускает скрипт insert_into.sh с этой информацией в качестве параметров для каждой строки. Скрипт insert_into.sh ищет по этим параметрам размер файла, который был скачан или загружен, в административной БД Nextcloud на PostgreSQL и записывает размер файла и всю другую информацию о трафике во вторую базу данных на MySQL.
cat /var/log/nextcloud/audit.log | awk -v k=$Num -F"," 'NR > k''{print $3,$4,$5 ,$9}' | awk -v m='"' -F'"' '{print " ","|"," ",m,$4,m," ","|"," ",m,$8,m," ","|"," ",m,$12,m," ","|"," "m,$16,m," ","|"," ",m,$17,m," ","|"," "}' | awk -F' \\| ' '{system("./insert_into.sh " $2 " " $3 " " $4 " " $5 " " $6)}'
Пайплайн состоит из четырёх команд.
Первая команда в конвейере передаёт содержимое файла audit.log по конвейеру утилите AWK.
Вторая команда вызывает утилиту AWK с опциями:
-v k=$Num
— говорит присвоить переменной AWK под именемk
значение переменнойNum
из скрипта Bash;-F","
— говорит использовать запятую в качестве полей в строках.
Также используется условие NR>k
,которое говорит начинать обработку со строки номером k + 1
(с последней строки, на которой закончилась обработка в прошлый раз).
Для каждой строки в этом вызове утилиты применяется функция-действие print $3,$4,$5 ,$9,
что выводит 3, 4, 5, 9 столбцы (используя в качестве разделителя запятую) каждой строки файла построчно в стандартный вывод, начиная со строки, на которой была остановлена обработка в прошлый раз.
Содержимое передаётся дальше по конвейеру команде вызывающей утилиту AWK с опциями:
–F’”’
— говорит использовать в качестве разделителя столбцов двойные кавычки;-v m='"'
— присваивает значение двойные кавычки переменной утилиты AWK с именемm
.
Для каждой строки применяется функция-действие print " ","|"," ",m,$4,m," ","|"," ",m,$8,m," ","|"," ",m,$12,m," ","|"," "m,$16,m," ","|"," ",m,$17,m," ","|"," " ,
что выводит в стандартный вывод 4, 8, 12, 16 столбцы, полученных по конвейеру строк построчно, используя разделитель кавычки, и добавляет в вывод между этими столбцами символы “ | ”,
что описано кодом m," ","|"," ",m ,
для дальнейшего удобства обработки этого вывода.
Вывод передаётся дальше по конвейеру команде, вызывающей утилиту AWK с опциями:
-F' \\| '
— что говорит использовать в качестве разделителя строку“ | “
(регулярное выражение‘\\|’
).
Для каждой строки применяется функция-действие system( "./insert_into.sh " $2 " " $3 " " $4 " " $5 " " $6)
, которое вызывает скрипт insert_into.sh с параметрами в виде столбцов из строки, переданной по конвейеру. Конструкция "command " parametr1 " " parametr2 " " parametr3 " " parametr4 " " parametr5
применяется для возможности передачи значения переменных из утилиты AWK в скрипт на bash (это называется соединение интерфейса командной строки (CLI), с содержанием функции-действие). Ниже приведено содержание скрипта insert_into.sh:
Path=$5
NAME=$3
modname=$(echo $NAME | sed -e "s/^.\{,0\}//;s/.\{,0\}$//")
Pathfile=$(echo $Path | sed -e "s/^.\{,0\}//;s/.\{,1\}$//")
NAME_USER=$(echo $modname)
ID=$(psql -U postgres --dbname='nextcloud_db' -c "SELECT object_id FROM oc_activity WHERE file='$Pathfile' AND affecteduser='$NAME_USER';" | sed '/-----------/d' | sed '/object_id/d' | sed '/row/d' )
for var in $ID
do
SIZE=$(psql -U postgres --dbname='nextcloud_db' -c "SELECT size FROM oc_filecache WHERE fileid=$var;")
mysql -h 192.168.2.22 --init-command="INSERT INTO nextcloud_audit (TIME, Remote_IP, username, operation, file_name, size) VALUES ('$1', '$2', '$3', '$4', '$5', '$SIZE'); " -e "quit" -unext --database=next -pPASSWORD
done
Приведу краткое описание этого скрипта.
В скрипт передаются параметры: тип операции (скачивание или загрузка), имя пользователя совершившего данную операцию, полный путь к файлу, дата проведения операции. По полному пути к файлу и имени пользователя, совершившего операцию, скрипт ищет в административной БД Nextlcoud на PostgreSQL размер скачанного или загруженного файла , а затем вместе с данными о типе операции и имени пользователя проводившего эту операцию, полного пути к файлу, даты проведения операции, записывает строку в таблицу в базе данных MySQL для проведённой операции.
Скрипт insert_into.sh вызывается из скрипта rassparsiv_audit_log.sh построчно для каждой строки лога audit.log, таким образом заполняя построчно таблицу в базе данных MySQL информацией по каждой операции: полный путь к файлу; тип выполненной операции; имя выполнившего операцию пользователя; размер файла; дата проведения операции.
В последней строчке скрипта rassparsiv_audit_log.sh находится номер последней строки, на которой остановилась обработка, и записывается в текстовый файл для начала следующей обработки с этой строки.
cat /var/log/nextcloud/audit.log | wc -l >> start_point.txt
Таким образом у меня получилось собрать скриптами на Bash всю нужную мне информацию о трафике из лога audit.log и административной БД Nextcloud на PostgreSQL и сложить её в БД на MySQL. Теперь можно делать выборки из этой базы данных и получать информацию о входящем и исходящем трафике на хранилище Nextcloud.
Вот как-то так. Спасибо за внимание!
Что ещё интересного есть в блоге Cloud4Y
→ Малоизвестный компьютер SWTPC 6800
→ Сделайте Linux похожим на Windows 95
→ Как распечатать цветной механический телевизор на 3D-принтере
→ WD-40: средство, которое может почти всё
→ Quantel Paintbox — устройство, изменившее мир телевизионных передач
Подписывайтесь на наш Telegram-канал, чтобы не пропустить очередную статью. Пишем только по делу.
13werwolf13
а можно вопрос? чому
>>
а не>
? для использования данных где я остановился достаточно хранить только одну точку.