Логируй больше! 1С + UPD + GELF + Graylog




Наличие производительной платформы управления логами — это жизненно важный элемент в ландшафте систем с высокой активностью. Рассмотрим один из подходов логирования активности систем на платформе 1С в Graylog.

Думаю, что на сегодняшний день нет необходимости подробно объяснять что такое 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

SystemInputs

 

LaunchNewGELFUDPInput

 

Input запущен и готов к работе:

InputCreated

Статичные поля могут быть добавлены дополнительно (например, для разделения по стримам). Не забываем проверять доступность портов на проксях/шлюзах/бранмаурэрах и т.д. и т.п.

В документации 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, наслаждаемся и используем платформу для разбора инцидентов, сбора аналитики и т.д. и т.п.

graylogExample

 

По сути данный подход реализует ту же функцию отправки данных в грэйлог, которую экранируют агенты, типа logstash, NXlog и т.д.
 

16 Comments

  1. KereberoS

    Статья начинается с чудесной фразы: «Думаю, что на сегодняшний день нет необходимости подробно объяснять что такое Graylog».

    Зачем в таком случае писать о Грейлог, если «об этом нет необходимости объяснять»?

    Reply
  2. nicxxx

    Одно дело знать, другое-уметь использовать

    Reply
  3. Scorpion4eg

    Чуть-чуть добавлю. У Graylog есть очень удобный механизм распределения общего потока сообщений на streams. А уже на этот stream можно навесить алерты, в т.ч. в slack.

    Мы так пока следим за ошибками в модулях.

    Ловишь исключение, получаешь сообщение в slack. В истории алертов находишь сообщение. По трек номеру сессии смотришь — а что пользователь делал, чтобы все сломать.

    Reply
  4. Lars Ulrich

    (1) На Пулитцера не претендую, была цель донести реализацию.

    Если Вы знали, как готовить Graylog, то объяснять действительно не нужно. Ну а если НЕ знали, но заинтересовались, то дополнительная цель достигнута 🙂

    Reply
  5. comol

    Статья огонь. Вопросы по теме:

    в чем преимущество GELF формата?

    Объём логов? Скорость записи? Скорость поиска?

    Reply
  6. Scorpion4eg

    (5) Грубо говоря — ни в чем. GELF — Graylog Extended Log Format.

    Это просто один из форматов, которые поддерживает Graylog и кастомные логи проще всего в нем слать

    Reply
  7. comol

    (6) В плане убирания ЖР в graylog в этом случае что мы выиграем?…

    Ещё что-то слышал про проксирование и формирование очереди через graylog… Если поток событий больше чем может переварить СУБД для хранения логов. Ну или если в СУБД для хранения логов нужно запись организовывать пакетно. Или вы только GELF формат у себя используете? А clickhouse graylog не поддерживает не в курсе?

    Reply
  8. Scorpion4eg

    (7) Здесь не подскажу. Если не ошибаюсь Graylog опирается на mongodb.

    Я не проксирую поток логов. У меня совсем отдельная история. Нашей команде потом логов, так чтобы не справлялась СУБД даже близко не получить.

    Но думаю можно завернуть поток логов на связку logstash-rabbitMQ-Graylog. Logstash умеет преобразовывать в gelf, а RabbitMQ возьмет на себя роль балансировщика. Ну и graylog умеет масштабироваться горизонтально — выделить несколько нод на сбор логов.

    Reply
  9. comol

    (8)

    Нашей команде потом логов, так чтобы не справлялась СУБД даже близко не получить.

    А вот тут можно подробнее? Ведь если лог-и собираются, то либо для поиска по ним чего-то либо для анализа…

    И в том и в том случае у вас СУБД, даже если она просто индексирует текстовые файлики. Ведь если там реально нереальный объём их надо индексировать?…

    СУБД не справится даже если оно поверх spark/hadoop или это что-то ооочень многонодное и кластеризованное?

    «не верю» (с).

    И как, кстати, вы умудрились получить в 1С такой поток логов что не справятся специализированные инструменты?

    Reply
  10. Scorpion4eg

    (9) Так. Похоже мы запутались.

    1. Логи собираем для того чтобы, быстро разбираться с исключениями на проде.

    2. У нас нет огромного потока логов. Я бы сказал что у нас наоборот очень скромный поток.

    3. Graylog я решил использовать, потому что а) неперевариваю Kibana б) не хочу писать запросы в Clickhouse для анализа ситуаций в) хочу иметь удобный, гибкий и быстро настраиваемый сервис уведомлений о факапах

    Reply
  11. acsent

    сами ошибки транслируете из ЖР? или тех журнал?

    Reply
  12. Lars Ulrich

    (11) У нас в ЖР кроме критичных ошибок больше ничего не пишется. Интеграционные логи фактически внешние.

    Reply
  13. acsent

    (12) Те вы сразу сами пишите во внешний лог?

    Reply
  14. herfis

    Предлагается писать лог напрямую во внешний лог-агрегатор внешней компонентой через сетку??

    Нууууу, такое…. Базовое логирование таким не заменишь. Собирать какие-то маркеры — можно, в принципе… Но зачем в онлайн упираться?

    Стоп, туплю. Это ж просто удобный способ донести данные из любого источника (тех же первичных логов). Тогда ок. Плюсанул.

    Reply
  15. Lars Ulrich

    (13) Да, сразу во внешний лог.

    Reply
  16. asved.ru
    2084 год. Искусственный интеллект на базе платформы 1C:Universe 128.256.512.65536 все еще поддерживает COM-объекты в силу низкого порога вхождения для разработчика.
    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *