Парсер технологического журнала (golang + redis + elasticsearch)

07.01.21

База данных - Технологический журнал

На просторах интернета, в том числе на данном ресурсе содержится разнообразное количество инструментов, позволяющих читать, трансформировать логи технологического журнала. Инструмент, который я описываю в данной статье, - является альтернативным вариантом, реализованным на стеке технологий Goroutines (golang) + Redis + Elasticsearch.

Скачать исходный код

Наименование Файл Версия Размер
Парсер технологического журнала (golang + redis + elasticsearch):
.rar 9,42Mb
11
.rar 1.0.0 9,42Mb 11 Скачать

Что такое технологический журнал, для чего он нужен и какая информация в нем содержится - можно прочитать, на мой взгляд, в самой детальной статье Юрия Пермитина (ну и конечно же - ИТС).

Про Elasticsearch так же уже достаточно статей, что это и как это применять в мире 1С. Например, вот несколько ссылок:

Elastic + filebeat + ТЖ 1С
Взаимодействие 1С со сторонними продуктами
Перенос всех логов в Elasticsearch

В данной статье я подробно опишу возможности предложенного стека, особенности, нюансы.

Итак, все инструменты, в рамках стека - open source, а так же являются кросс-платформенными. Верхнеуровнево, архитектура решения выглядит следующим образом:

 

Что есть что на данной схеме:

Каталог тех. журнала 1С - каталог, в котором содержаться непосредственно логи. Уровень вложенности не важен, так как рекурсивно будут просмотрены все каталоги и прочитаны файлы с расширением *.log.

techLog1C - инстанс парсера. Одновременно может быть запущено несколько инстансов. Парсер принимает на вход массив файлов *.log производит парсинг, после чего отправляет данные в Elasticsearch. Парсер может работать многопоточно внутри своего инстанса а так же сам пишет логи в ходе своей работы (все это конфигурируется в файле settings.yaml - детальные настройки будет приведены ниже). Лучшей практикой является кейс, когда логи инкрементно забираются с продуктового сервера с некоторой периодичностью на служебную машину, где уже непосредственно стартует парсер. Такой подход не приводит к дополнительной нагрузке на продуктовый сервер. 

Redis - NoSQL key-value СУБД. В стеке выполняет роль кэша, для хранения параметров файлов, которые обрабатываются в текущий момент времени и те, которые были обработаны (последняя позиция файла). Почему не используется простой текстовый файл? Все просто - парсер работает в многопоточном режиме, что требует доступ до файла в режиме записи из нескольких потоков. Redis позволяет решать следующие кейсы:

  1. Если файла тех. журнала уже нет, то при запуске парсера анализируются ключи в redis базе и проверяется существование файлов. Если файлы не существуют - ключи таких файлов удаляются.
  2. Так же при запуске еще одного инстанса парсера - будут пропущены файлы тех. журнала, обрабатываемые другими инстансами.

Несмотря на то, что redis все значения хранит в оперативной памяти - периодически служба производит запись на диск, в случае перезагрузки или сбоя службы - последние сохраненные значения будут восстановлены с диска.

Наиболее свежие и стабильные сборки redis осуществляются под linux, но и для windows есть сборки от Microsoft Open Tech.

Elasticsearch - используется как конечная точка хранения распарсенных логов 1С. Нереляционная база данных Elasticsearch позволяет достаточно оперативно получать необходимую информацию, используя поисковые обратные индексы. В связке с Kibana - можно строить выборки, используя декларативный KSQL язык запросов.

1. - Использование запросов KSQL

2. - Распарсенные поля, которые можно использовать в качестве выбранных полей.

При использовании расширения XPACK (30 day free trial) можно задействовать модуль машинного обучения (Machine Learning), что позволит выявлять аномалии и различные зависимости от показателей тех журнала и журнала операционной системы, например утечки памяти.

Описание настроек парсера

Все настройки указываются в файле settings.yaml

# Расположение логов тех журнала 1С
patch: "D:\\tmp\\1C_event_log\\1C_event_log"
#
# Параметры подключения к Redis
redis_addr: "localhost:6379"
redis_login: ""
redis_password: ""
redis_database: 0
#
# Параметры подключения к Elasticsearch
elastic_addr: "http://localhost:9200"
elastic_login: ""
elastic_password: ""
elastic_maxretries: 10
elastic_bulksize: 2000000
#
# Правила формирования индекса Elasticsearch
# Пример: "tech_journal_{event}_yyyyMMddhh", где event - CONN, EXCP, etc...
elastic_indx: "tech_journal_{event}_yyyyMMddhh"
#
# Типы событий тех журнала, которые могут содержать длинные строки '...' и переносы строк \n
tech_log_details_events: "Context|Txt|Descr|DeadlockConnectionIntersections|ManagerList|ServerList|Sql|Sdbl|Eds"
#
# Путь, где будут распологаться логи программы
patch_logfile: "D:\\tmp\\techLogData\\log"
#
# Глубина фиксации ошибок при работе программы:
#   1 - только ошибки
#   2 - ошибки и предупреждения 
#   3 - ошибки, предупреждения и информация
log_level: 3
#
# Уровень параллелизма
maxdop: 14
#
# 0 - отключена сортировка файлов по размеру, 1 - сортировка по убыванию, 2 - сортировка по возрастанию
# полезно включать при массовых операциях, для равномерного распределения файлов по потокам
sorting: 0

Служба Redis может быть запущена на другой машине в сети, так же как и инстанс Elasticsearch. Для этого используются параметры redis_addrelastic_addr. Redis из коробки поддерживает аутентификацию, в то время как Elasticsearch по умолчанию полностью открыт для доступа. Задать базовую аутентификацию для Elasticsearch можно через nginx

Redis содержит внутри себя 16 баз данных, их нумерация целочисленная от 0 до 15. Рекомендуется задать параметр redis_database для случаев, когда в вашей организации уже используется Redis и необходимо изолировать существующие базы.

Параметры elastic_maxretrieselastic_bulksize - позволяют управлять поведением массовой вставки в индексы Elasticsearch. Elasticsearch имеет ограничения на операции массовой вставки bulk api. Из версии к версии они меняются. Ключевыми факторами, влиящими на успешную массовую загрузку являются - дисковая подсистема и процессор, помимо, конечно же объема пакета данных, отправляемых в массовом запросе. Операция bulk может выполняться параллельно из нескольких сеансов. В случае большого суммарного объема данных, которые отправляются сеансами - может произойти ситуация, когда Elastic просто не успеет обновить карту индексов и произвести индексацию загружаемых документов, что непременно приведет к ошибке и остановке службы Elasticsearch. Чтобы избежать этого - рекомендуется подбирать объем данных, отправляемых одним сеансов (в байтах), за что отвечает параметр elastic_bulksize.  elastic_maxretries - число попыток повторной отправки пакета, в случае возникновения ошибок загрузки одного пакета данных.

Правило формирования наименования индекса можно задавать в параметре elastic_indx. Предложенного варианта формирования вполне достаточно для большинства случаев.

Параметры событий, которые могут содержать длинные строки с символами переноса строк лучше сразу указать в tech_log_details_events. По умолчанию, в настройках приведен перечень таких параметров, но если считаете, что указаны не все - их можно внести в настройки. Такой подход значительно сокращает время на парсинг файлов, но и несет в себе существенный минус - в случае появления нового параметра в событиях, например, с выходом новой версии платформы, может возникнуть проблема при формировании полей индексов в Elasticsearch в следствии некорректного парсинга. 

Программа так же ведет логи своей работы, но не пишет их в Elastic, т.к. любой из инструментов стека может оказаться недоступен. Глубина логирования задается параметром log_level. По умолчанию он = 3 - то есть полная информация о поведении программы. Логи пишутся в формате json, что упрощает процедуру анализа впоследствии.

Парсер, как было указано ранее, может работать многопоточно, что особенно полезно когда у вас много логов, они тяжелые (например, включен полный тех журнал), или же вам необходимо произвести первоначальное чтение существующих логов. Количество потоков указывается в параметре maxdop. При использовании параметра sorting можно ускорить операцию чтения исторических логов. Если задать значение параметра = 2 (по возрастанию размера файла), то операции создания карты индекса будут производиться быстрее, т.к. файлы меньшего объема и содержат небольшое количество документов. Но лучшей практикой является описание карты индексов внутри map файлов, которые использует парсер (см. каталог maps). При таком подходе, при создании нового индекса, будет полноценно создаваться карта, а затем в индекс будут загружаться документы, что позволит исключить операции переформирования карты при каждой вставке документа. Тем более, что операция переформирования карты - достаточно дорогостоящая и блокирующая при операциях массовой вставки.

Особенности настройки Elasticsearch

Elasticsearch работает на JVM, поэтому очень требователен к настройкам памяти. По умолчанию размер кучи установлен в 1Gb, что крайне мало при массовой операции вставки документов в индексы Elasticsearch.

  1. XMX/XMS рекомендуется установить равным половине оперативной памяти, доступной физической/виртуальной машине. Например, если у вас 16Gb, то возможный вариант настройки: -Xms8G -Xmx8G Документация

  2. Очистка старых индексов (использование index lifecycle policy). Чем детальнее технологический журнал - тем сильнее будет расти его объем, а значит и индексы в Elasticsearch, это может привести к нехватке свободного места на дисках, где хранятся индексы. Лучшая практика - спустя N дней удалять индексы. Все что необходимо - задать политику жизненного цикла индексов https://www.elastic.co/guide/en/elasticsearch/reference/current/set-up-lifecycle-policy.html После этого задать темплейт, который будет включать индексы тех журнала

PUT _template/tech_journal_template
{
  "index_patterns": ["tech-*"],                 
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "index.lifecycle.name": "tech_journal_policy"    
  }
}

Но при таком подходе - политика применится только к вновь создаваемым индексам. Чтобы ее применить к уже существующим, нужно выполнить следующий запрос:

PUT tech_*/_settings
{
  "index.lifecycle.name": "tech_journal_policy" 
}

Известные проблемы:

  1. circuit_breaking_exception,  [request] Data too large, data for [<reused_arrays>] would be larger than limit of: Измените параметры XMX/XMS
  2. es_rejected_execution_exception: rejected execution of coordinating operation Уменьшите уровень параллелизма (maxdop), подберите оптимальный размер блока на единицу bulk операции (elastic_bulksize), увеличьте параметр elastic_maxretries в settings.yaml файле.
  3. Долгая индексация, update mapping index. После загрузки каждого документа - если не задана карта индекса - карта создается, что создает накладные расходы, при количестве документов > 1 млн, обновление карты может не уложиться в таймаут по умолчанию (30 сек.). Поэтому, рекомендуется создавать map карты индекса (см. каталог maps)

Производительность

При включенном тех журнале, содержащем следующие настройки:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/tech-log">

<log location="S:\1C_event_log\all" history="25">
  <event>
      <eq property="Name" value="EXCP"/>
  </event>
  <event>
      <eq property="Name" value="CONN"/>
  </event>
  <event>
      <eq property="Name" value="PROC"/>
  </event>
  <event>
      <eq property="Name" value="ADMIN"/>
  </event>
  <event>
      <eq property="Name" value="SESN"/>
  </event>
  <event>
      <eq property="Name" value="CLSTR"/>
  </event>
   <property name="all"/>
</log>

<log location="S:\1C_event_log\tlocks" history="1">
  <event>
      <eq property="Name" value="TLOCK"/>
  </event>
  <event>
      <eq property="Name" value="TTIMEOUT"/>
  </event>
  <event>
      <eq property="Name" value="TDEADLOCK"/>
  </event>
   <property name="all"/>
</log>
	
</config>

суммарный размер лог файлов за сутки составляет 4,3 Gb. Инстанс парсера, запущенный при настройке 14 потоков на отдельной машине core i3 (v gen) с 16 Gb оперативной памяти, не ssd - обработал логи за 19 минут (bulk size - 200mb). При инкрементном запуске парсера каждую минуту - скорость обработки инкрементных данных варьируется от 5 до 14 секунд.

Самым оптимальным - является запуск парсера с одновременным включением тех журнала. В настройках тех журнала нужно указывать только те события, которые вам действительно нужны, а так же использовать отборы событий по параметрам, например - duration, p:processName и.т.д. Это позволит сократить объемы выходных логов, что положительно скажется на парсинге и хранении логов внутри Elasticsearch.

Резюме

Парсер является полностью открытым, расположен на:

https://github.com/NuclearAPK/go-techLog1C

Можно поучаствовать в его совершенствовании и оптимизации.

Так же буду рад конструктивным замечаниям и предложениям. 

технологический журнал redis elasticsearch многопоточность golang go goroutines логи linux github shmell

См. также

Магия преобразований Vector, часть 2: технологический журнал

Технологический журнал Мониторинг Абонемент ($m)

Как легко и быстро с помощью специализированных решений собирать, парсить и передавать логи и метрики.

1 стартмани

15.11.2023    836    4    AlexSTAL    0    

8

Магия преобразований: ЖР, ТЖ, RAS/RAC, логи - универсальное решение Vector

Мониторинг Журнал регистрации Технологический журнал Абонемент ($m)

Как легко и быстро с помощью специализированных решений собирать, парсить и передавать логи и метрики.

1 стартмани

13.11.2023    3150    4    AlexSTAL    0    

42

«Монитор» – простой анализ производительности

Администрирование СУБД Технологический журнал Бесплатно (free)

Для расследования проблем производительности недостаточно просто проанализировать технологический журнал. Нужен парсинг контекста событий, его сопоставление с информацией из Extended Events и логов, агрегация огромного количества информации.

21.09.2023    5892    Andreynikus    14    

80

Экспорт технологического журнала 1С в Elastic с помощью Logstash

Технологический журнал Платформа 1С v8.3 Абонемент ($m)

Целью данного решения является организация хранения и анализа данных из технологического журнала 1С с использованием стека Elasticsearch + Logstash + Kibana.

5 стартмани

18.09.2023    3491    huxuxuya    3    

23

Мобильный помощник эксперта 1С (приложение android, позволяющее строить отчеты на СКД по логам технологического журнала и не только)

Технологический журнал Мониторинг Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Приложение на мобильной платформе 1С Предприятие, позволяющее разбирать все, что может быть разобрано в командной строке linux, и выводить полученный результат типовыми методами системы компоновки данных. По мотивам направления Эксперт по технологическим вопросам

16.05.2023    3441    capitan    0    

23

Разбор технологического журнала без боли и страданий

Технологический журнал Абонемент ($m)

Технологический журнал - мощный инструмент логирования, используемый для анализа проблем производительности 1С. Но он обладает одним огромным недостатком, в "сыром виде" он почти не поддается адекватному анализу из-за своей структуры. Существует довольно много способов "разобрать" технологический журнал, но все опробованные способы обладают теми или иными недостатками. Предлагаю вам мой вариант "велосипеда" для разбора ТЖ и хранения разобранного в различных форматах.

1 стартмани

12.12.2022    8367    39    Segate    26    

88

Выполняем в СУБД запрос из ТЖ

Технологический журнал Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка для подстановки или нумерации параметров в тексте запроса из технологического журнала.

1 стартмани

24.11.2022    2901    3    VKislitsin    1    

17
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Smaylukk 185 04.02.21 13:24 Сейчас в теме
Ни в статье, ни на гитхабе не указано, что надо установить Golang.
Попробовал запустить. Исправил файл settings.yaml.
При попытке запустить парсер - пишет "no go files listed".
Подскажите, куда копать?
+
2. Shmell 535 04.02.21 17:17 Сейчас в теме
(1) на гитхабе я добавил релиз, который содержит бинарник для win64 и debian
https://github.com/NuclearAPK/go-techLog1C/releases/tag/0.1

для запуска в этом случае не требуется Golang.

Если будете использовать в среде windows то для настройки задания планировщика нужно прописать рабочую папку в параметрах.
+
3. buganov 200 18.05.21 08:23 Сейчас в теме
Можно пояснить, для чего в стеке прокладка в виде редиски? Почему сразу не булкать в эластик?
+
4. Shmell 535 18.05.21 09:18 Сейчас в теме
(3) в публикации указано для каких целей.
+
5. krund 03.06.21 15:27 Сейчас в теме
Вадим подскажи пожалуйста что нужно сделать в самой kibane чтобы увидеть данные отправленные парсером в elastic?
+
6. Shmell 535 04.06.21 05:24 Сейчас в теме
(5)
1. Для начала нужно создать паттерн индекса. Он должен начинаться так же как и наименование индекса

2. Далее, заходим в discovery и выбираем наш индекс паттерн

3. Если все ок, можно начать крутить дашборды, настраивать алерты, подключать xpack итд

см. приложенные файлы
Прикрепленные файлы:
+
7. krund 04.06.21 08:55 Сейчас в теме
Вадим что то не так у меня. Что я где не доделал?
Прикрепленные файлы:
+
8. user1461477 16.06.21 15:47 Сейчас в теме
Когда что-то пошло не так
Прикрепленные файлы:
+
9. user1461477 16.06.21 15:49 Сейчас в теме
Нет, конечно, работа внушает. Красиво
Но вот такой облом с отсутствием шаблона.
Обидно очень
+
11. Shmell 535 16.06.21 19:20 Сейчас в теме
(9) вы уверены что к нужной публикации комментарий написали?
+
12. user1461477 17.06.21 12:25 Сейчас в теме
(11) Доброго времени. Что, эта красивая картинка - не ваша работа? Или ваша, но обсуждается где-то в другом месте? Или ваша, но не обсуждается? В таком случае, прошу прощения, больше не буду.
+
13. Shmell 535 17.06.21 14:54 Сейчас в теме
14. user1461477 17.06.21 14:59 Сейчас в теме
(13) упс. извините, пожалуйста
Shmell; +1
10. user1461477 16.06.21 16:15 Сейчас в теме
без галки реалтайма - то же
--
Нет соответствия шаблону!
38:50.579133-11,SDBL,3,process=1CV8C,OSThread=13068,Usr=DefUser,DBMS=DBV8DBEng,DataBase=base,Trans=1,Sdbl='INS ERT IN TO Reference47 (Marked, PredefinedID, OwnerID, Description, Fld247, Fld248, Fld249, Fld250, Fld251, Fld252, Fld253, Fld254, Fld255, Fld256, VT257.(LineNo258, Fld259, Fld260, Fld261, Fld262)) VALUES(FALSE,0x00000000000000000000000000000000,35:8dafe164f0d0485b11ebce9c54b39a3f,"31:39.759001-0","31:39.759001-0,CONN,0,process=1CV8C,OSThread=16532,Txt=''Ping direction statistics: address=[::1]:1560,pingTimeout=15000,pingPeriod=3000,period=10063,packetsSent=3,avgResponseTime=0,maxResponseTime=0,packetsTimedOut=0,packetsLost=0,packetsLostAndFound=1''",DATETIME(2021,6,16,15,31,39),759001,0,38:00000000000000000000000000000000,2,44:8dafe164f0d0485b11ebce9c54b39a47,46:8dafe164f0d0485b11ebce9c54b39a4b,0,48:8dafe164f0d0485b11ebce9ca0312b66,((1,45:8dafe164f0d0485b11ebce9c54b39a4f,"Ping direction statistics: address=[::1]:1560,pingTimeout=15000,pingPeriod=3000,period=10063,packetsSent=3,avgResponseTime=0,maxResponseTime=0,packetsTimedOut=0,packetsLost=0,packetsLostAndFound=1",0,""),(2,45:8dafe164f0d0485b11ebce9c54b39a4e,"16532",0,""),(3,45:8dafe164f0d0485b11ebce9c54b39a4d,"1CV8C",0,"")))',Rows=1,Context='

Справочник.Замеры.Команда.ВыполнитьЗагрузку.МодульКоманды : 11 : ОбновлениеДанныхРегламентное.АвтозагрузкаРегламентное(ПараметрКоманды);
ОбщийМодуль.ОбновлениеДанныхРегламентное.Модуль : 21 : ЗагрузкаФайловТЖ(Замер, ФайлыДляЗагрузки);
ОбщийМодуль.ОбновлениеДанныхРегламентное.Модуль : 170 : ОбновлениеДанных.РазобратьФайлВСправочник(Замер, строкарезультата.ПолноеИмя);
ОбщийМодуль.ОбновлениеДанных.Модуль : 463 : Справочники.СобытияЗамера.ЗаписатьСобытие(СтруктураЗаписи);
Справочник.СобытияЗамера.МодульМенеджера : 13 : СобытиеОбъект.Записать();'
{ОбщийМодуль.ОбновлениеДанных.Модуль(375)}: ВызватьИсключение "Нет соответствия шаблону! " + СтрокаТекста;
{ОбщийМодуль.ОбновлениеДанныхРегламентное.Модуль(170)}: ОбновлениеДанных.РазобратьФайлВСправочник(Замер, строкарезультата.ПолноеИмя);
{ОбщийМодуль.ОбновлениеДанныхРегламентное.Модуль(21)}: ЗагрузкаФайловТЖ(Замер, ФайлыДляЗагрузки);
{Справочник.Замеры.Команда.ВыполнитьЗагрузку.МодульКоманды(11)}: ОбновлениеДанныхРегламентное.АвтозагрузкаРегламентное(ПараметрКоманды);
{Справочник.Замеры.Команда.ВыполнитьЗагрузку.МодульКоманды(4)}: ОбработкаКомандыСервер(ПараметрКоманды);
+
Оставьте свое сообщение