Автор: Александр Тряпкин, DevOps компании Hostkey Здравствуйте, уважаемые читатели Habr! В этой статье я хочу поделиться своим опытом решения задачи сбора логов при помощи Go. Как начинающий DevOps, я выбрал для изучения и решения рабочих задач язык программирования Go. Для отправки syslog-логов доступна библиотeка syslog, но увы, она нам не подходит, поскольку данный пакет недоступен на Windows, а задача — сделать мультиплатформенный отправщик логов установки системы на удаленный syslog-сервер. Дополнительно есть потребность отправлять логи в кастомном формате, а именно — в json, для упрощения их последующей обработки. При этом важно, чтобы программа выполнялась одинаково на Linux и на Windows, не требовала установки, выполняла свою задачу и удалялась из системы, поэтому придется изобрести небольшой велосипед. Приступим. В качестве принимающей стороны мы будем использовать syslog-ng. Рассмотрим параметры, которые нам интересны в части сбора логов — от специфики параметров зависит, как мы будем их отправлять. Сначала указываем новый source для приема логов с удаленных серверов, и тут есть варианты — в зависимости от наших потребностей можно собирать логи по UDP, TCP, а также использовать TLS для шифрования и аутентификации. Наиболее интересным вариантом является TLS, но мы рассмотрим и другие методы — от простого к более сложному. 1) UDP. Для сбора логов по UDP потребуется следующие параметры в конфигурации syslog-ng: Порт по умолчанию — 514/UDP, документация предупреждает о необходимости увеличить UDP-буфер при высокой интенсивности отправки логов, иначе возможны потери сообщений. В случае потери пакетов логи также будут потеряны,так что это не оптимальный вариант. 2) TCP. Вариант лишен вышеуказанных проблем и, согласно документации, применяется по умолчанию. Примерный конфиг следующий:     3) TLS. Для использования этого протокола необходимо настроить сервер, в официальной документации есть достаточно подробная пошаговая инструкция. Пример:   При таком варианте настройки мы будем принимать логи только от клиентов, прошедших аутентификацию. Иначе говоря, клиент использует действующий сертификат и логи приходят с IP-адреса или доменного имени, под который сертификат выпущен. Если нет задачи аутентифицировать пользователей, то можно указать peer-verify (no) и получить только шифрование. Рассмотрев различные варианты, мы решили создать небольшую программу, которая будет отправлять наши логи. Для начала разберемся, как отправить syslog сообщение серверу так, чтобы он его принял и обработал. Из документации мы видим, что принимаемые сообщения должны соответствовать протоколу RFC3164 или RFC5424. Но поскольку это не окончательный вариант, попробуем отправить лог, используя RFC3164, который выглядит следующим образом: Теперь разберемся, что значит каждая из частей сообщения: <30> — заголовок, содержащий информацию о severity и facility. Закодированную информацию можно расшифровать с помощью таблицы, в данном случае там содержится facility — system и severity — info. Dec 25 21:55:36 — timestamp. 19202.example.ru — hostname. Systemd[1]: — тег сообщения, указывающий, какой программой было отправлено сообщение. Starting Cleanup of Temporary Directories… — само сообщение. Попробуем отправить сообщение в таком формате в наш тестовый сервер syslog-ng, настроенный на прием логов по UDP. Для этого мы используем библиотеку net:   Выполнив код, мы видим, что сервер получил наши сообщения и обработал. Сообщения записаны в указанный файл: Теперь отправим логи по TCP. Перенастраиваем сервер на получение логов по TCP и пробуем:   Но что мы видим: что-то пошло не так, два сообщения соединены в одно, и второе сообщение не распарсилось. Когда мы отправляли логи по UDP, данная проблема не возникала, поскольку каждое сообщение уходит в своем пакете и обрабатывается отдельно. Решение на самом деле простое — я упустил, что каждое сообщение должно заканчиваться переносом строки \n. Правим и пробуем: Теперь все ок! Мы разобрались как отправить сообщение, пришло время применить это знание. Следует учитывать, что, если мы хотим отправить сообщения в формате json (в дальнейшем это сильно облегчит задачу по обработке логов), нам необходимо отключить парсинг в syslog-ng. Для этого достаточно добавить flags (no-parse) в source. Далее будем пробовать отправить логи по протоколу TLS и в json-формате уже в виде полноценной программы: Пробуем выполнить, передав в программу все те же две строки, и сервер получает наши логи:   Эта программа — одна из первых, написанных мною на Go. В процессе ее создания я разобрался, как работает протокол syslog, и освоил азы нового для меня языка программирования. Программа позволила унифицировать отправку логов на разных операционных системах, независимо от семейства, в тех местах, где нет возможности пользоваться syslog-ng. В настоящее время мы адаптируем созданную программу для дальнейшего применения в инфраструктуре нашей компании.