Создание плагина
Эта страница предназначена для тех, кто заинтересован в разработке собственного плагина (независимого сборщика данных) для Zabbix агент 2.
Пользовательский плагин позволяет расширить функциональность Zabbix агент 2 сверх предоставляемых встроенных плагинов и загружаемых плагинов.
Каждый плагин представляет собой пакет Go, который определяет структуру и реализует один или несколько интерфейсов (Exporter, Configurator, Runner). Дополнительную информацию см. в разделах Интерфейсы плагинов и Схема соединений.
Это руководство поможет вам создать пользовательский загружаемый плагин.
Дополнительные рекомендации также можно найти в репозитории:
Что вы создадите
Это пошаговое руководство по созданию простого загружаемого плагина с именем MyIP.
Этот плагин будет реализовывать один ключ элемента данных (myip), возвращающий внешний IP-адрес узла сети агента Zabbix.
Шаг 1: Настройка
- Плагин представляет собой стандартный модуль Go.
Начните с инициализации файла
go.modв каталоге плагина, чтобы отслеживать зависимости плагина:
cd path/to/plugins/myip # Перейдите в каталог вашего плагина
go mod init myip
- Установите обязательную зависимость Zabbix Go SDK (
golang.zabbix.com/sdk):
go get golang.zabbix.com/sdk@$LATEST_COMMIT_HASH
Замените $LATEST_COMMIT_HASH на хеш последнего коммита HEAD из репозитория golang.zabbix.com/sdk в соответствующей ветке релиза.
Например:
go get golang.zabbix.com/sdk@af85407
Обратите внимание, что управление версиями для golang.zabbix.com/sdk в настоящее время не поддерживается, но это может измениться в будущем.
Дополнительные зависимости при необходимости можно установить с помощью go get.
- Создайте пустой файл
main.goдля исходного кода плагина:
touch main.go
Теперь начальная настройка завершена, и плагин готов к разработке.
Шаг 2: Структура плагина
Модуль golang.zabbix.com/sdk, установленный на предыдущем шаге, предоставляет необходимую основу для разработки плагинов и обеспечивает единообразную структуру всех плагинов.
- Настройте базовый поток выполнения.
Начните с определения основного потока выполнения плагина. Добавьте следующий код в main.go:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
Это задает базовый поток выполнения для плагина. Позже функция run будет содержать основную логику плагина.
- Изучите интерфейсы плагина.
Плагин Zabbix агент 2 должен быть представлен структурой, реализующей интерфейсы из пакета golang.zabbix.com/sdk/plugin:
- Accessor — определяет основные методы, которые должны реализовывать все плагины, например установку имени плагина и обработку тайм-аутов ключей элементов данных.
- Один или несколько из следующих функциональных интерфейсов плагина:
- Exporter — выполняет опрос и возвращает значение (или значения), ничего или ошибку; часто используется вместе с интерфейсом Collector.
- Collector — управляет периодическим сбором данных.
- Runner — определяет процедуры запуска и остановки плагина.
- Watcher — позволяет реализовать независимый опрос метрик в обход внутреннего планировщика агента; полезен для мониторинга на основе ловушек или событий.
- Configurator — определяет, как плагин считывает и применяет свои настройки конфигурации.
Вы можете либо реализовать эти интерфейсы самостоятельно, либо использовать стандартные реализации, предоставляемые Zabbix Go SDK, изменяя их по мере необходимости.
В этом руководстве используются стандартные реализации.
- Создайте структуру плагина.
Теперь импортируйте пакет plugin и создайте структуру myIP, которая встраивает структуру plugin.Base:
import "golang.zabbix.com/sdk/plugin"
type myIP struct {
plugin.Base
}
В настоящее время структура myIP удовлетворяет интерфейсу Accessor.
Позже в этом руководстве будет добавлен метод для реализации одного из функциональных интерфейсов плагина — Exporter.
Шаг 3: Определите ключи элементов данных
Вашему плагину нужны ключи элементов данных для сбора данных и их передачи на сервер Zabbix или прокси.
- Импортируйте пакет errs для обработки ошибок:
import "golang.zabbix.com/sdk/errs"
- Зарегистрируйте ключи элементов данных с помощью функции
plugin.RegisterMetrics()внутри функцииrun():
func run() error {
p := &myIP{}
// Register the `myip` item key.
err := plugin.RegisterMetrics(
p,
"MyIP", // Plugin name
"myip", // Item key name
"Returns the host's IP address.", // Item key description
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
return nil
}
Чтобы зарегистрировать несколько ключей элементов данных, повторите параметры имя метрики и описание для каждой метрики.
Например:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
Шаг 4: Настройка обработчика
Обработчик обеспечивает взаимодействие между агентом и плагином.
- Импортируйте пакет container:
import "golang.zabbix.com/sdk/plugin/container"
- Внутри функции
run()добавьте код для создания и настройки обработчика:
func run() error {
p := &myIP{}
// Register the `myip` item key.
err := plugin.RegisterMetrics(
p,
"MyIP", // Plugin name
"myip", // Item key name
"Returns the host's IP address.", // Item key description
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// Create a new handler.
h, err := container.NewHandler("MyIP") // Plugin name
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// Setup logging to forward logs from the plugin to the agent.
// Available via p.Logger.Infof, p.Logger.Debugf, etc.
p.Logger = h
// Start plugin execution.
// Blocks until a termination request is received from the agent.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "failed to execute plugin handler")
}
return nil
}
Шаг 5: Реализуйте сбор данных
Сбор данных выполняется через интерфейс Exporter, который описывает метод Export:
func Export(
key string, // Ключ элемента данных для сбора.
params []string, // Аргументы, передаваемые ключу элемента данных (`myip[arg1, arg2]`).
context ContextProvider // Метаданные о сборе данных ключа элемента данных.
) (any, error)
- Импортируйте необходимые пакеты для HTTP-запросов и чтения ответа:
import (
"io"
"net/http"
)
- Реализуйте метод
Exportдля структурыmyIP:
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Плагин может использовать различную логику сбора данных в зависимости от параметра `key`.
// Эта реализация только проверяет, что указанный `key` поддерживается.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// Журнал будет перенаправлен в журнал agent 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Соберите данные и верните их.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "failed to get IP address")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "failed to read response body")
}
return string(body), nil
}
Шаг 6: Сборка и настройка плагина
- Чтобы собрать плагин, выполните:
go mod tidy
go build
Это должно создать исполняемый файл myip в текущем каталоге.
- Настройте агент Zabbix 2 на использование плагина:
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Замените $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE на путь к файлу myip, созданному на шаге 5.
Имя плагина в имени параметра конфигурации (MyIP в этом руководстве) должно совпадать с именем плагина, определённым в функции plugin.RegisterMetrics().
- Чтобы протестировать плагин и его элемент данных
myip, выполните:
zabbix_agent2 -c /etc/zabbix_agent2.conf -t myip
Вывод должен содержать внешний IP-адрес вашего узла сети и выглядеть примерно так:
myip [s|192.0.2.0]
На этом всё — вы создали простой загружаемый плагин для агента Zabbix 2. Поздравляем!
Полный исходный код
package main
import (
"io"
"net/http"
"golang.zabbix.com/sdk/errs"
"golang.zabbix.com/sdk/plugin"
"golang.zabbix.com/sdk/plugin/container"
)
var _ plugin.Exporter = (*myIP)(nil)
type myIP struct {
plugin.Base
}
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
p := &myIP{}
// Регистрируем ключ элемента данных `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Имя плагина
"myip", // Имя ключа элемента данных
"Returns the host's IP address.", // Описание ключа элемента данных
)
if err != nil {
return errs.Wrap(err, "failed to register metrics")
}
// Создаем новый обработчик.
h, err := container.NewHandler("MyIP") // Имя плагина
if err != nil {
return errs.Wrap(err, "failed to create new handler")
}
// Настраиваем журналирование для перенаправления журналов из плагина в агент.
// Доступно через p.Logger.Infof, p.Logger.Debugf и т.д.
p.Logger = h
// Запускаем выполнение плагина.
// Блокирует выполнение до получения запроса на завершение от агента.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "failed to execute plugin handler")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// Плагин может использовать различную логику сбора данных в зависимости от параметра `key`.
// Эта реализация только проверяет, что предоставленный `key` поддерживается.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// Журнал будет перенаправлен в журнал агента 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Собираем данные и возвращаем их.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "failed to get IP address")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "failed to read response body")
}
return string(body), nil
}