Каталог решений - Логируй больше! 1С + UPD + GELF + Graylog

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

Логируй больше! 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 и т.д.
 

has been added to your cart:
Оформление заказа