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