Думаю, что на сегодняшний день нет необходимости подробно объяснять что такое Graylog. В области управления логами это платформа для централизованного сбора, хранения, индексации и анализа структурированных и не структурированных данных из практически любых источников.
Вопрос управления логами становится все более острым и для систем на платформе 1С:Предприятие , т.к. области их применения, объемы обрабатываемых данных и нагрузки растут. Встроенная в платформу 1C подсистема логирования не всегда удовлетворяет критериям скорости, архитектуры и удобства использования, а так же требует использования сторонних средств для более глубокого анализа и визуализации.
Рассмотрим достаточно простой способ реализации логирования действий/событий/ошибок и т.д. в Graylog для решений на плафторме 1С:Предприятие. Возможно, он больше подходит для кастомных решений, либо типовых решений, для которых допустима кастомизация, но от этого не теряет своей актуальности.
Исходим из того, что:
— в нашей инфраструктуре уже развернут Graylog-кластер (примеры статья для версии 2.4, но на текущий момент уже доступна версия Graylog 3.0);
— у нас есть доступ к Graylog правами администратора;
— для передачи по UDP используем замечательную ВК от Сергея Serginio Смирнова;
Способов интеграции с Graylog достаточно много. Нас интересует предоставляемое API, протокол передачи данных UDP и формат GELF (Graylog Extended Log Format). Почему UDP, а не HTTP, думаю, понятно, хотя возможность передачи GELF-сообщений по HTTP так же есть.
Создадим новый GELF UDP Input: в консоли Graylog System -> Inputs -> Select input: GELF UDP -> Launch new input
Input запущен и готов к работе:
Статичные поля могут быть добавлены дополнительно (например, для разделения по стримам). Не забываем проверять доступность портов на проксях/шлюзах/бранмаурэрах и т.д. и т.п.
В документации Graylog формат GELF и его ограничения хорошо описаны. Ограничимся тем, что GELF-сообщение — это данные в JSON-формате, содержащие набор обязательных, не обязательных и произвольных полей.
Предположим, что мы логируем входящий/исходящий http-трафик нашей системы. Тогда пример структуры GELF-сообщения может иметь вид:
// GELF-сообщение
//
Функция ПолучитьСтруктуруЗаписиЛога() Экспорт
СтруктураЗаписиЛога = Новый Структура;
// обязательные поля
СтруктураЗаписиЛога.Вставить("version", "1.1");
СтруктураЗаписиЛога.Вставить("host", ИмяКомпьютера());
СтруктураЗаписиЛога.Вставить("short_message", "");
СтруктураЗаписиЛога.Вставить("full_message", "");
СтруктураЗаписиЛога.Вставить("level", 6);
// произвольные поля
СтруктураЗаписиЛога.Вставить("_systemName", ИмяТекущейБазы()); // имя текущей системы
СтруктураЗаписиЛога.Вставить("_baseUrl", ""); // базовый URL запроса
СтруктураЗаписиЛога.Вставить("_relativeUrl", ""); // относительный URL запроса
СтруктураЗаписиЛога.Вставить("_requestHeaders", ""); // заголовки запроса
СтруктураЗаписиЛога.Вставить("_requestBody", ""); // тело запроса
СтруктураЗаписиЛога.Вставить("_responseResult", ""); // результат ответа (технологическое поле)
СтруктураЗаписиЛога.Вставить("_responseStatusCode", ""); // код состояния http
СтруктураЗаписиЛога.Вставить("_responseHeaders", ""); // заголовки ответа
СтруктураЗаписиЛога.Вставить("_responseBody", ""); // тело ответа
СтруктураЗаписиЛога.Вставить("_duration", ""); // длительность обработки http-вызова
СтруктураЗаписиЛога.Вставить("_logType", ""); // тип лога: innerRequest-входящий вызов; outerRequest-исходящий вызов
СтруктураЗаписиЛога.Вставить("_messageType", ""); // произвольный тип сообщения
СтруктураЗаписиЛога.Вставить("_objectUid", ""); // UID объекта базы, с которым может быть связан текущий вызов
СтруктураЗаписиЛога.Вставить("_objectType", ""); // тип объекта базы, с которым может быть связан текущий вызов
Возврат СтруктураЗаписиЛога;
КонецФункции
Сформируем новое сообщение лога:
//
//
Функция ПолучитьЗаписьЛогаHTTPЗапроса(ТипЗаписиЛога, БазовыйURL = "", ОтносительныйURL = "", ЗапросЗаголовки = "", ЗапросТело = "", ОтветЗаголовки = "", ОтветТело = "", КодСостояния = 200, Результат = 1, Объект = "", Длительность = 0, УровеньСообщения = 6) Экспорт
СтруктураЗаписиЛога = ПолучитьСтруктуруЗаписиЛога();
ОбъектУникальныйИдентификатор = ?(ЗначениеЗаполнено(Объект), СокрЛП(Объект.УникальныйИдентификатор()), "");
ОбъектТип = СокрЛП(ТипЗнч(Объект));
СтруктураЗаписиЛога.short_message = Лев(БазовыйURL, 200);
СтруктураЗаписиЛога.full_message = Лев(БазовыйURL, 400) + ?(ЗначениеЗаполнено(ОтносительныйURL), "/" + Лев(ОтносительныйURL, 200), "");
СтруктураЗаписиЛога.level = УровеньСообщения;
СтруктураЗаписиЛога._logType = ТипЗаписиЛога;
СтруктураЗаписиЛога._baseUrl = БазовыйURL;
СтруктураЗаписиЛога._relativeUrl = ОтносительныйURL;
СтруктураЗаписиЛога._requestHeaders = ЗапросЗаголовки;
СтруктураЗаписиЛога._requestBody = ЗапросТело;
СтруктураЗаписиЛога._responseResult = Результат;
СтруктураЗаписиЛога._responseStatusCode = КодСостояния;
СтруктураЗаписиЛога._responseHeaders = ОтветЗаголовки;
СтруктураЗаписиЛога._responseBody = ОтветТело;
СтруктураЗаписиЛога._objectUid = ОбъектУникальныйИдентификатор;
СтруктураЗаписиЛога._objectType = ОбъектТип;
СтруктураЗаписиЛога._duration = Длительность;
Возврат СтруктураЗаписиЛога;
КонецФункции
Выполним отправку сообщения:
ВнешняяСистемаЛогирования = Новый Структура("Сервер, Порт", "graylog.mydomain", 15555);
СтруктураЗаписиЛога = ПолучитьЗаписьЛогаHTTPЗапроса(ТипЗаписиВнешнегоЛога_ВходящееСообщение(), БазовыйURL, ОтносительныйURL, ЗапросЗаголовки, ТелоЗапроса, ОтветЗаголовки, ОтветТело, КодСостояния, Результат, ДлительностьВыполнения);
ВыполнитьЗапросUDP(ВнешняяСистемаЛогирования, JSON(СтруктураЗаписиЛога));
Определение используемых методов:
//
//
Функция JSON(Структура)Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписьJSON.ПроверятьСтруктуру = Ложь;
ЗаписатьJSON(ЗаписьJSON, Структура);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
//
//
Функция ВыполнитьЗапросUDP(Настройки, ТелоЗапроса, КодировкаСообщения = "utf8") Экспорт
ОписаниеОшибки = "";
Попытка
NetObjectToIDispatch = Новый COMОбъект("NetObjectToIDispatch45");
udpClient = NetObjectToIDispatch.СоздатьОбъект("System.Net.Sockets.UdpClient");
Хост = Настройки.Сервер;
Порт = Настройки.Порт;
Если НРег(КодировкаСообщения) = "utf8" Тогда
SystemTextEncoding = NetObjectToIDispatch.ПолучитьТип("System.Text.Encoding").UTF8;
ИначеЕсли НРег(КодировкаСообщения) = "unicode" Тогда
SystemTextEncoding = NetObjectToIDispatch.ПолучитьТип("System.Text.Encoding").Unicode;
Иначе
SystemTextEncoding = NetObjectToIDispatch.ПолучитьТип("System.Text.Encoding").ASCII;
КонецЕсли;
sendBytes = SystemTextEncoding.GetBytes(СтрЗаменить(СтрЗаменить(ТелоЗапроса, Символы.ВК, " "), Символы.ПС, " "));
udpClient.Send(sendBytes, sendBytes.getLength(), Хост, Порт);
udpClient.Close();
Исключение
ОписаниеОшибки = ОписаниеОшибки();
Сообщить(ОписаниеОшибки);
КонецПопытки;
NetObjectToIDispatch = Неопределено;
udpClient = Неопределено;
SystemTextEncoding = Неопределено;
sendBytes = Неопределено;
КонецФункции
//
//
Функция ТипЗаписиВнешнегоЛога_ВходящееСообщение() Экспорт Возврат "innerRequest"; КонецФункции
//
//
Функция ТипЗаписиВнешнегоЛога_ИсходящееСообщение() Экспорт Возврат "outerRequest"; КонецФункции
В результате получаем данные в Graylog, наслаждаемся и используем платформу для разбора инцидентов, сбора аналитики и т.д. и т.п.
По сути данный подход реализует ту же функцию отправки данных в грэйлог, которую экранируют агенты, типа logstash, NXlog и т.д.
Статья начинается с чудесной фразы: «Думаю, что на сегодняшний день нет необходимости подробно объяснять что такое Graylog».
Зачем в таком случае писать о Грейлог, если «об этом нет необходимости объяснять»?
Одно дело знать, другое-уметь использовать
Чуть-чуть добавлю. У Graylog есть очень удобный механизм распределения общего потока сообщений на streams. А уже на этот stream можно навесить алерты, в т.ч. в slack.
Мы так пока следим за ошибками в модулях.
Ловишь исключение, получаешь сообщение в slack. В истории алертов находишь сообщение. По трек номеру сессии смотришь — а что пользователь делал, чтобы все сломать.
(1) На Пулитцера не претендую, была цель донести реализацию.
Если Вы знали, как готовить Graylog, то объяснять действительно не нужно. Ну а если НЕ знали, но заинтересовались, то дополнительная цель достигнута 🙂
Статья огонь. Вопросы по теме:
в чем преимущество GELF формата?
Объём логов? Скорость записи? Скорость поиска?
(5) Грубо говоря — ни в чем. GELF — Graylog Extended Log Format.
Это просто один из форматов, которые поддерживает Graylog и кастомные логи проще всего в нем слать
(6) В плане убирания ЖР в graylog в этом случае что мы выиграем?…
Ещё что-то слышал про проксирование и формирование очереди через graylog… Если поток событий больше чем может переварить СУБД для хранения логов. Ну или если в СУБД для хранения логов нужно запись организовывать пакетно. Или вы только GELF формат у себя используете? А clickhouse graylog не поддерживает не в курсе?
(7) Здесь не подскажу. Если не ошибаюсь Graylog опирается на mongodb.
Я не проксирую поток логов. У меня совсем отдельная история. Нашей команде потом логов, так чтобы не справлялась СУБД даже близко не получить.
Но думаю можно завернуть поток логов на связку logstash-rabbitMQ-Graylog. Logstash умеет преобразовывать в gelf, а RabbitMQ возьмет на себя роль балансировщика. Ну и graylog умеет масштабироваться горизонтально — выделить несколько нод на сбор логов.
(8)
А вот тут можно подробнее? Ведь если лог-и собираются, то либо для поиска по ним чего-то либо для анализа…
И в том и в том случае у вас СУБД, даже если она просто индексирует текстовые файлики. Ведь если там реально нереальный объём их надо индексировать?…
СУБД не справится даже если оно поверх spark/hadoop или это что-то ооочень многонодное и кластеризованное?
«не верю» (с).
И как, кстати, вы умудрились получить в 1С такой поток логов что не справятся специализированные инструменты?
(9) Так. Похоже мы запутались.
1. Логи собираем для того чтобы, быстро разбираться с исключениями на проде.
2. У нас нет огромного потока логов. Я бы сказал что у нас наоборот очень скромный поток.
3. Graylog я решил использовать, потому что а) неперевариваю Kibana б) не хочу писать запросы в Clickhouse для анализа ситуаций в) хочу иметь удобный, гибкий и быстро настраиваемый сервис уведомлений о факапах
сами ошибки транслируете из ЖР? или тех журнал?
(11) У нас в ЖР кроме критичных ошибок больше ничего не пишется. Интеграционные логи фактически внешние.
(12) Те вы сразу сами пишите во внешний лог?
Предлагается писать лог напрямую во внешний лог-агрегатор внешней компонентой через сетку??
Стоп, туплю. Это ж просто удобный способ донести данные из любого источника (тех же первичных логов). Тогда ок. Плюсанул.Нууууу, такое…. Базовое логирование таким не заменишь. Собирать какие-то маркеры — можно, в принципе… Но зачем в онлайн упираться?
(13) Да, сразу во внешний лог.