![](https://habrastorage.org/getpro/habr/upload_files/5ba/6f3/bf7/5ba6f3bf786acd502595786856f04804.png)
Одна из самых частых и понятных задач в разработке и эксплуатации — доставка логов. И дальше в статье мы с вами используем Fluent Bit для доставки логов из виртуальной машины в сервис Yandex Cloud Logging.
Шаг 1. Пишем логи в systemd
Возможно, у вас уже есть сервис, поставку чьих логов вы хотели бы настроить. Тогда переходите к шагу 2. Если же нет, то можно воспользоваться следующим кодом на Python, чтобы генерировать тестовые логи, которые впоследствии мы будем отправлять.
Итак, нам понадобится Python 3.6 и выше.
1. Заведём директорию, куда сложим все необходимые файлы:
sudo mkdir /usr/local/bin/logtest
cd /usr/local/bin/logtest
2. Добавим следующий код в файл logtest.py:
import logging
import random
import sys
import time
from systemdlogging.toolbox import check_for_systemd
from systemdlogging.toolbox import SystemdFormatter
from systemdlogging.toolbox import SystemdHandler
# Следующие несколько строк могут быть заменены на вызов `systemdlogging.toolbox.init_systemd_logging`
# Но я приведу этот код полностью в целях демонстрации.
# Проверяем доступен ли systemd
systemd_ok = check_for_systemd()
if systemd_ok:
handler = SystemdHandler()
# syslog_id: значение которое будет использовано в поле SYSLOG_IDENTIFIER.
handler.syslog_id = ''
handler.setFormatter(SystemdFormatter())
# получаем инстанс объекта логгера
logger = logging.getLogger()
logger.addHandler(handler)
else:
# Ветка будет использована для локальной отладки, если у вас нет systemd (MacOS, Windows)
logger = logging.getLogger(__name__)
# Выводить логи будем в STDOUT
handler = logging.StreamHandler(stream=sys.stdout)
handler.setFormatter(logging.Formatter(
'[%(levelname)s] %(code)d %(message)s'
))
logger.addHandler(handler)
# Опционально можно настроить уровень логирования по умолчанию
logger.setLevel(logging.DEBUG)
# Мы могли бы обойтись и простым логированием случайных чисел, но я решил генерировать URL-подобные значения.
PATHS = [
'/',
'/admin',
'/hello',
'/docs',
]
PARAMS = [
'foo',
'bar',
'query',
'search',
None
]
def fake_url():
path = random.choice(PATHS)
param = random.choice(PARAMS)
if param:
val = random.randint(0, 100)
param += '=%s' % val
code = random.choices([200, 400, 404, 500], weights=[10, 2, 2, 1])[0]
return '?'.join(filter(None, [path, param])), code
if __name__ == '__main__':
while True:
# создаем пару код и значение URL
path, code = fake_url()
# Если код 200, то пишем в лог с уровнем Info
# Cloud Logging ориентируется на текстовое написание уровня логирования, поэтому в `context` передадим
# дополнительное значение `SEVERITY`. Оно попадет в journald и сможет быть прочитано в плагине yc-logging.
# В продуктовом коде это стоит вынести в `SystemdHandler`, чтобы не потерять,
# но в примере я оставлю так для наглядности.
if code == 200:
logger.info(
'Path: %s',
path,
extra={"code": code, "context": {"SEVERITY": "info"}},
)
# Иначе с уровнем Error
else:
logger.error(
'Error: %s',
path,
extra={"code": code, "context": {"SEVERITY": "error"}},
)
# Ждем 1 секунду, чтобы излишне не засорять журнал
time.sleep(1)
3. Заведём virtualenv и установим в него все нужные зависимости:
sudo apt install python3-pip python3.8-venv
python -m venv venv
source venv/bin/activate
pip3 install systemd-logging
Теперь нам понадобится скрипт logtest.sh, который будет вызываться systemd для запуска нашего сервиса:
#!/bin/bash
SCRIPT_PATH=$(dirname "$(realpath "$0")")
. "$SCRIPT_PATH/venv/bin/activate"
python "$SCRIPT_PATH/logtest.py"
4. Создадим файл logtest.service с описанием нашего сервиса:
[Unit]
Description=Sample to show logging from a Python application to systemd
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/logtest/logtest.sh
Restart=on-abort
[Install]
WantedBy=multi-user.target
5. Этот файл может лежать в любом каталоге, который вам нравится. Я бы предложил положить его с исходным кодом на Python для этого приложения. Но чтобы systemd нашёл файл, нам нужно придерживаться соглашения о том, куда складывать unit-файлы. Не буду вдаваться в подробности о systemd (тут на целую книгу хватит, это выходит за рамки поста в блоге) — убедимся, что наш файл модуля имеет symlink в /etc/systemd/system. Для этого выполним команду:
sudo ln -s "$(pwd)/logtest.service" \
/etc/systemd/system/logtest.service
6. Теперь можно перезагрузить systemd:
sudo systemctl daemon-reload
7. Проверим, что всё ОК:
systemctl status logtest.service
Там должно быть написано, что сервис загружен, но не активен.
8. Запустим systemd:
systemctl start logtest.service
Теперь, если снова посмотреть статус, то там должно быть active (running).
Шаг 2. Ставим Fluent Bit
Но сначала проясним пару моментов.
![И там и там птичка, так в чём же разница? И там и там птичка, так в чём же разница?](https://habrastorage.org/getpro/habr/upload_files/d08/500/9d6/d085009d6236a6526eab7c877739c17d.jpeg)
Fluent Bit vs Fluentd
Чтобы упростить работу с логами, когда-то появился Fluentd. Он был написан на Ruby и со временем вырос в целую экосистему, которая включает и Fluent Bit. Быстрое сравнение приведено в таблице:
![https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit https://docs.fluentbit.io/manual/about/fluentd-and-fluent-bit](https://habrastorage.org/getpro/habr/upload_files/6d6/ab7/7a2/6d6ab77a2fcf5141238dfe5ca813dd06.png)
Как видно, для установки Fluent Bit не нужны никакие зависимости типа Ruby. И хотя к нему есть меньше плагинов, чем для Fluentd, зато он потребляет значительно меньше памяти.
Теперь разберёмся, как его поставить
1. Добавим GPG-ключ, которым подписаны пакеты в репозитории Fluent Bit.
$ wget -qO - https://packages.fluentbit.io/fluentbit.key | sudo apt-key add -
2. В Ubuntu добавим в файл /etc/apt/sources.list строчку:
deb https://packages.fluentbit.io/ubuntu/focal focal main
3. Затем обновим индексы:
sudo apt-get update
4. Теперь можно установить последнюю версию td-agent-bit:
sudo apt-get install td-agent-bit
5. После этого его остаётся только перезапустить:
sudo service td-agent-bit start
6. Что всё ОК, можно проверить командой:
sudo service td-agent-bit status
Там должно быть active (running).
Шаг 3. Подключаем плагин
Fluent Bit поддерживает плагины, написанные на Go. Это экспериментальный, но вполне рабочий API.
1. Итак, клонируем репозиторий с кодом плагина:
git clone https://github.com/yandex-cloud/fluent-bit-plugin-yandex.git
2. Для начала нам понадобится Go. Инструкция по установке тут.
3. Теперь скомпилируем библиотеку:
export fluent_bit_version=1.8.6
export plugin_version=dev
CGO_ENABLED=1 go build -buildmode=c-shared \
-o ./yc-logging.so \
-ldflags "-X main.PluginVersion=${plugin_version}" \
-ldflags "-X main.FluentBitVersion=${fluent_bit_version}"
4. Копируем полученную библиотеку:
sudo cp yc-logging.so /usr/lib/td-agent-bit/yc-logging.so
5. И регистрируем её в файле с конфигурацией плагинов /etc/td-agent-bit/plugins.conf:
[PLUGINS]
Path /usr/lib/td-agent-bit/yc-logging.so
6. Вносим изменения в конфиг самого сервиса. folder_id укажите свой. Если к ВМ привязан service account с правами писать в Yandex Cloud Logging, то authorization укажите instance-service-account. Другие варианты авторизации и значение остальных параметров можно посмотреть тут.
[INPUT]
Name systemd
Tag host.*
Systemd_Filter _SYSTEMD_UNIT=logtest.service
[OUTPUT]
Name yc-logging
Match *
resource_type logtest
folder_id b1g***
message_key MESSAGE
level_key SEVERITY
default_level WARN
authorization instance-service-account
7. Перезагружаем сервис td-agent-bit:
sudo systemctl restart td-agent-bit
8. Отлично. Теперь можно убедиться, что логи поступают:
![Yandex Cloud Logging Yandex Cloud Logging](https://habrastorage.org/getpro/habr/upload_files/5f4/449/8bb/5f44498bbdea3f166f4bc63c5857d757.png)
P. S. Yandex Cloud Logging — это serverless-сервис в Yandex.Cloud. Если вам интересна экосистема Serverless-сервисов и все, что с этим связано, заходите в сообщество в Telegram, где можно обсудить serverless в целом.
Настройка работы Fluent Bit в контейнерах ещё проще. Но о ней я расскажу в следующей публикации.