Zabbix 3.4: Массовый сбор данных на примерах счетчика Меркурий и smartmontools

c5b8bad9a58545459d8ebac4620f5e9b.png

Всем привет, ранее мы уже упоминали о возможностях по массовому сбору данных в новой версии опенсорс системы мониторинга Zabbix 3.4. Теперь остановимся на этом функционале поподробнее, и чтобы было нагляднее, расскажем о нем на двух примерах:

  • сбор всех данных за раз, полученных в JSON от консольной утилиты счетчика электроэнергии Меркурий 236
  • сбор показателей S.M. A.R.T. жестких дисков и SSD, полученных в табличном виде от smartmontools.


А в чем была собственно проблема?


Собирать данные через консольные утилиты или вызовы API данные можно было и ранее, но существовали сложности:

  • медленные запуски утилит каждый раз, на каждый нужный элемент данных
  • обращение к ресурсу (диск, порт, счетчик, API приложения) на каждый элемент данных
  • парсинг результата нужно было делать внешними скриптами/утилитами
  • а если потом нужно было поправить парсинг — приходилось опять обновлять UserParameters или скрипты
  • кроме всего прочего, одновременные запросы от нескольких Zabbix pollers приводили к ошибке при обращении, например, к последовательному порту.


В общем, дело было так:

9a982dcac4824ad8b04ac6bf27b22254.png

А с появлением зависимых элементов данных, стало возможно так:

e481207bef204c25b19a6713bd9d628f.png

Как это работает?

  • В Zabbix 3.4 источником данных может выступать другой элемент данных, который называется родительским или мастер-элементом. Такой элемент может, например, содержать массив данных в формате JSON, XML или фривольном текстовом формате.
  • В момент поступления новых данных в родительский элемент, остальные элементы данных, которые называются зависимыми, обращаются к родительскому элементу и при помощи таких функций препроцессинга как JSON path, XPath или Regex выделяют из текста нужную метрику.


Кстати, препроцессинг — тоже нововведение 3.4, он реализован добавлением новых процессов preprocessing_manager и preprocessing_worker на Zabbix-сервере. Поэтому, если вы обновляетесь с 3.2 — не забудьте обновить шаблон для сервера, чтобы мониторить их работу.

Переходим к примерам.

Меркурий 236


e2914108def64856bac857bc4a68cfca.jpeg
Представим, что на нашем проекте, кроме контейнеров, виртуальных машин, приложений, сетевых устройств, баз данных, бизнес показателей и всего прочего требующего контроля, присутствует необходимость мониторить показатели электросети и другой «инженерки», как, например, климатическое оборудование. Используются стандартные для нашей средней полосы устройства: трехфазный счетчик электроэнергии Меркурий 236 АRT-01 PQRS с интерфейсом RS-485, поверх которого общение происходит через проприетарный протокол производителя.

Задача ответственная — сразу собирать показатели напряжения, мощности, тока, потребления, частоты. Подключить такой прибор к серверу с Zabbix агентом — задача посильная — достаточно будет серийного порта с RS-485, например, в форме USB адаптера. Но как прочитать данные? Если бы не github и добрые люди, поделившиеся своим решением для умного дома, писать бы нам модуль к Zabbix, который бы мы учили разговаривать на протоколе счетчика и опрашивать показатели.

Утилита простая и удобная (за что автору большое человеческое спасибо) подключается к счетчику на указанный порт, считывает данные и отдает нам в виде текста, CSV или JSON.

Давайте попробуем установить и запустить:

git clone https://github.com/Shden/mercury236.git
cd mercury236
make
./mercury236 /dev/ttyS0 --help
Usage: mercury236 RS485 [OPTIONS] ...
RS485 address of RS485 dongle (e.g. /dev/ttyUSB0), required
--debug to print extra debug info
--testRun dry run to see output sample, no hardware required
Output formatting:
....
--help prints this screen

Запускается! Отлично, подключаем счетчик, опрашиваем, получаем JSON:

./mercury236 /dev/ttyS0 --json

{
                "U": {
                               "p1": 0.35,
                               "p2": 0.35,
                               "p3": 226.86
                },
                "I": {
                               "p1": 0.00,
                               "p2": 0.00,
                               "p3": 0.39
                },
                "CosF": {
                               "p1": 0.00,
                               "p2": 0.00,
                               "p3": 0.60,
                               "sum": 0.60
                },
                "F": 50.00,
                "A": {
                               "p1": 41943.03,
                               "p2": 41943.03,
                               "p3": 41943.03
                },
                "P": {
                               "p1": 0.00,
                               "p2": 0.00,
                               "p3": 53.45,
                               "sum": 53.45
                },
                "S": {
                               "p1": 0.00,
                               "p2": 0.00,
                               "p3": 89.83,
                               "sum": 89.83
                },
                "PR": {
                               "ap": 120.51
                },
                "PR-day": {
                               "ap": 86.00
                },
                "PR-night": {
                               "ap": 34.51
                },
                "PY": {
                               "ap": 0.00
                },
                "PT": {
                               "ap": 0.04
                }
}


В итоге утилита уже сделала всю сложную работу за нас, реализовав протокол общения с счетчиком, вытащив данные, да еще и предложила нам это в виде удобного JSON объекта. Вот только раньше просто так мы ей не смогли бы воспользоваться — пришлось бы писать обвязку в виде скриптов, а самое главное — реализовывать механизм контроля доступа к среде последовательного порта. Ведь если два поллера Zabbix одновременно обратятся к нему — один за током третьей фазы 3, а другой — за током фазы 2, у нас не вернулось бы ничего.

В 3.4 все становится гораздо проще, и мы теперь быстро и легко можем передавать данные сторонних консольных утилит в Zabbix, не прибегая к оберточным скриптам, и не запуская по 10 раз одно и тоже на каждый элемент данных отдельно. Итак,

Настроим запуск утилиты mercury236 из Zabbix


sudo cp mercury236 /etc/zabbix/scripts
cd /etc/zabbix/scripts
chmod +x mercury236
sudo usermod -G dialout zabbix

Для запуска скрипта, создадим в конфиге Zabbix-агента новый UserParameter:

UserParameter=mercury236[*],/etc/zabbix/scripts/mercury236 $1 $2


Сохраняем файл, не забываем перезапустить наш Zabbix-агент.

Теперь создадим в новом шаблоне родительский элемент данных:

6363f3a9883c4fcf8131e0b6b483c12a.png

Как видите, в родительском элементе данных нет ничего особенного — просто проверка через UserParameter Zabbix-агента. А это значит, что и нет никаких ограничений на то, какой тип проверки может выступать в роли родительского элемента — здесь могут быть и данные полученные через Zabbix trapper или через Внешние проверки. Единственное, мы выбрали Тип информации — Text и срок хранения истории в 1 день — хранить дольше мы собираемся метрики отдельно в зависимых элементах (можно не хранить данные вообще в родительском элементе, выставив срок хранения 0). Обратите внимание, что препроцессинг в этом элементе данных мы не трогаем.

Настроим получение наших метрик счетчика


Для того чтобы начать создавать зависимые элементы данных, можно воспользоваться новым помощником. Ну или просто нажать «Создать элемент данных»:

4ef481290a964f00a48f36c44c94cae0.png

Создадим элемент данных для напряжения первой фазы, выберем:

  • Тип: Зависимый элемент данных
  • Основной элемент данных: mercury-get


89b4564f64464979a4e1107281b7e39a.png

Затем во вкладке «Предобработка» добавим наше выражение JSON Path:

Путь JSON: $.U.p1

de51525dd7a24148a2e9f7da2556e221.png

Кстати, маленький совет. Чтобы не тратить много времени на отладку и ловлю ошибок, перед тем как заполнять JSON Path можно быстро проверить правильность выражения онлайн, например здесь: jsonpath.com, скопировав туда JSON, полученный от утилиты.

Аналогичным образом создаем другие интересующие нас метрики. В том числе — для накопленной энергии по дневному тарифу.

Для этого создадим новый элемент данных и выберем:

  • Тип: Зависимый элемент данных
  • Основной элемент данных: mercury-get


А вот во вкладке «Предобработка» обратите внимания на два нюанса:

  • будем использовать нотацию с квадратными скобками, так как в пути JSON есть дефис
  • препроцессинг может быть многошаговым, например здесь результата первого шага умножим на 1000, чтобы получить Вт*ч из кВт*ч


55b783af815b409a8be50c39868b9ce4.png

Проделаем аналогично для остальных ключевых метрик счетчика, в итоге получим вот такой список:

019718d050a943e0bbd22dd4b38bb9ca.png

Доведем наш шаблон до ума


Чтобы шаблон был законченным, добавим триггеры, используя макросы, делая его максимально гибким. Не забываем про зависимости триггеров.

bc1dea3fd5c54048bf3207cfae6cec7b.png

Что получилось


Шаблон готов, данные побежали, посмотрим, что у нас получилось:

780d4619f1e44486bd077eff7554de1c.png

Все последние данные, собранные за одно обращение:

6286aecb0c1541a08c4cb36220526c98.png

Обратите внимание, что время сбора всех метрик абсолютно идентично.

Итоговый шаблон для счетчика доступен на репозитории решений на share.zabbix.com здесь.

Подведем итоги:

  • переиспользовали хорошую программку и не тратили время на написание своей реализации сбора данных по протоколу Меркурий
  • UserParameter остался, но схлопнулся до простого вызова. По сути можно даже system.run[] использовать
  • cкрипты-обертки тоже не писали. Всё распарсили через JSON path в шаблоне
  • cчетчик не мучали сильно, один запрос — все нужные нам данные разом.


Smartctl и smartmontools


65b2d921c9404eaf8cbdeb8a0f256491.png

Давно мы уже писали на хабре, как можно контролировать S.M. A.R.T. жестких дисков, чтобы успеть их вовремя поменять, через использование UserParameters. Такой подход работает, но он не был лишен недостатков:

  • избыточные запуски утилиты smartctl, а она в свою очередь каждый раз обращалась к контроллеру жесткого диска
  • пришлось делать отдельный парсинг для Linux и Windows. Особенно больно с этим сейчас работать в Win: (for /F… так… экранируем двойные кавычки еще кавычками…. Аааа!!!)


Постараемся в 3.4 от всего этого избавится.

Случай с smartmontools имеет два отличия от примера со счетчиком выше:

  • smartctl нам JSON не возвращает
  • дисков в сервере может быть различное количество, поэтому нам нужно использовать низкоуровневое обнаружение (LLD).


Но ничего страшного! Во-первых, зависимые элементы данных работают и для LLD, а во-вторых у нас среди preprocessing-фильтров есть и PCRE regex. Воспользуемся им, чтобы вытащить нужные показатели из не супер сильно структурированного ответа утилиты. Примерно такого:

85d44e1029b84e3e991285c404b8da1d.PNG

Приступим.

Упрощаем UserParameters


Было:

UserParameter=uHDD[*], sudo smartctl -A $1| grep -i "$2"| tail -1| cut -c 88-|cut -f1 -d' '
UserParameter=uHDD.model.[*],sudo smartctl -i $1 |grep -i "Device Model"| cut -f2 -d: |tr -d " "
UserParameter=uHDD.sn.[*],sudo smartctl -i $1 |grep -i "Serial Number"| cut -f2 -d: |tr -d " "
UserParameter=uHDD.health.[*],sudo smartctl -H $1 |grep -i "test"| cut -f2 -d: |tr -d " "
UserParameter=uHDD.errorlog.[*],sudo smartctl -l error $1 |grep -i "ATA Error Count"| cut -f2 -d: |tr -d " "
UserParameter=uHDD.discovery,sudo /etc/zabbix/scripts/smartctl-disks-discovery.pl


Стало:

UserParameter=uHDD.A[*],sudo smartctl -A $1
UserParameter=uHDD.i[*],sudo smartctl -i $1
UserParameter=uHDD.health[*],sudo smartctl -H $1
UserParameter=uHDD.discovery,sudo /etc/zabbix/scripts/smartctl-disks-discovery.pl


Аналогично делаем и для Windows, попутно избавляясь от CMD магии с использование for /F и find. Посмотреть можно тут.

Создаем новые родительские элементы данных


Для сбора всех атрибутов S.M. A.R.T. создадим прототип мастер-элемента данных:

c44d31ea2c83415397e877fd65fa63e9.png

Как и в предыдущем примере, ничего особенного настраивать не надо. Только Тип информации — Text, а Период хранения — 1 день.

Для сбора результатов тестов и инвентарных данных нам потребуется запускать smartctl с другими ключами. Поэтому аналогично создадим еще два элемента данных:

  • uHDD.i[»{#DISKNAME}»]
  • uHDD.health[»{#DISKNAME}»]


Настроим получение наших атрибутов S.M. A.R.T. диска


Создадим зависимый элемент данных для атрибута 5, Reallocated:

8e6b932ebb9544f1ab973f5d33b44f78.png

И во вкладке «Предобработка» используем регулярное выражение:

2d255186bd9b45b582fa795a315bab05.png

И так же как и с JSON Path, чтобы не тратить много времени на отладку и ловлю ошибок, перед тем как заполнять regex, удобно быстро проверить правильность выражения онлайн, например здесь: regex101.com скопировав туда наш вывод smartctl.

В итоге получим такой вот список прототипов:

54b38fc80e9f4766a38ef527b63e4102.png

Тестируем, смотрим что получилось


Для двух HDD:

ca2238241bec4c51944d6425344b4a0f.png

Для SSD под Windows:

384d4245a17f443c89fbe85ab61fa4b5.png

Подведем итоги примера с smartmontools:

  • мы убрали весь парсинг из UserParameters
  • нет внешних скриптов (кроме LLD), нет внешних зависимостей, весь парсинг происходит на Zabbix-сервере, там его легко посмотреть и подправить, если нужно
  • когда утилита или API не возвращает XML/JSON — не беда, всегда можно попробовать использовать регулярные выражения
  • жесткие диски больше не мучаем — сначала достаем весь список параметров S.M. A.R.T., а затем уже на Zabbix-сервере раскладываем его по метрикам.


Обновленный шаблон (заодно обновили триггеры, добавили элементы данных для SSD) доступен на репозитории решений на share.zabbix.com здесь.

В завершении


Массовой сбор метрик — простой и легкий способ уменьшить нагрузку на сеть и на ресурсы наблюдаемых систем, а также снизить потребность во внешних скриптах. Уверены, что многим пользователям Zabbix он придется по душе.

P.S. Статья также доступна на английском в нашем блоге.

© Habrahabr.ru