Всем привет! Снова на связи Алексей Холодаев из Cloud4Y. 

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

Что такое Nextcloud, знают, наверное, многие читатели. Поэтому ограничусь небольшим определением: Nextcloud — это программный комплекс, который реализует облачное хранилище данных. Удобная штука, по правде говоря.

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

Какие данные о трафике я хотел собирать: 

  1. Тип операции (скачивание файла с хранилища или загрузка в хранилище Nextcloud).

  2. Полное расположение файла, с которым что-то делали.

  3. Имена пользователей, которые производили данные операции.

  4. Дата и время выполнения операций.

  5. Размер скачанных и загруженных файлов. 

Поясню первый пункт. Типы операций «скачивание с Nextcloud» и «загрузка на Nextcloud» обладают подтипами: напрямую через web-интерфейс, через общие локальные ссылки (Internal link share), через общие публичные ссылки (Public link share). Мне нужно было учитывать все подтипы этих операций. Мониторинг осуществлялся локально на одном сервере с Nextcloud, а не на внешних сервисах. 

В ходе решения этой задачи я не нашёл встроенных инструментов и плагинов для Nextcloud. Но поиск привёл меня к административной базе данных Nextcloud, которая представляла собой базу данных на PostgreSQL. Эта БД хранила в своих таблицах информацию об активностях пользователей. В том числе об исходящем и входящем трафике. Что я нашёл в ней:

  1. Тип операции (скачивание файлов с хранилища Nextcloud через общие публичные ссылки, либо локальные ссылки или загрузка файлов на хранилище Nextcloud).

  2. Размер файлов, над которыми производились операции (скачивание, загрузка, etc).

  3. Пользователи, которые совершали эти операции.

  4. Дата и время выполнения этих операций.

Казалось бы, всё. Я близок к решению своей задачи и могу брать всю нужную мне информацию из этой БД. Но увы, в ней не было данных по операциям скачивания непосредственно через 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-канал, чтобы не пропустить очередную статью. Пишем только по делу.

Комментарии (1)


  1. 13werwolf13
    07.06.2022 06:26

    wc -l >> start_point.txt 

    а можно вопрос? чому >> а не > ? для использования данных где я остановился достаточно хранить только одну точку.