这是一个分步教程,介绍如何为 Zabbix agent 2 create 一个简单的可加载插件。
您还可以使用 example repository 作为模板或指南来创建您自己的插件。
本教程演示如何create一个新的可加载插件MyIP。 该插件将实现一个监控项键值myip,用于返回运行Zabbix agent 2的主机的外部IP地址。
1。插件是一个标准的 Go 模块。
首先在插件目录中初始化 go.mod
file,以跟踪插件依赖项:
2。安装必需的依赖项 Zabbix Go SDK(golang.zabbix.com/sdk
):
将 $LATEST_COMMIT_HASH
替换为 golang.zabbix.com/sdk
repository 在相应发布分支中的最新 HEAD
提交哈希值。
例如:
请注意,目前 golang.zabbix.com/sdk
尚不支持版本控制,但将来可能会发生变化。
可以按需使用 go get
安装其他依赖项。
3。为插件源代码创建一个空的 main.go
file:
现在初始设置已完成,插件已准备好进行开发。
golang.zabbix.com/sdk
模块(已在前期步骤中安装)为插件开发提供了必要框架,并确保所有插件具有统一结构。
首先定义插件的主执行流程。将以下代码添加至main.go
文件:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
这段代码构建了插件的基础执行框架。 后续将在run函数中实现插件的核心逻辑。
Zabbix agent 2插件应通过实现golang.zabbix.com/sdk/plugin
包中的接口结构体来定义:
开发者可选择自行实现这些接口,或直接使用Zabbix Go SDK提供的默认实现并按需修改。 本教程采用默认实现方案。
现在importplugin包并create嵌入plugin.Base
结构体的myIP
结构体:
当前myIP结构体已满足Accessor接口要求。 本教程后续将添加实现功能接口的方法——Exporter
方法。
您的插件需要使用监控项键来收集数据,并将其提供给Zabbix server或proxy。
1。导入errs包以进行错误处理:
2。使用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
}
要注册多个监控项键,请为每个指标重复参数metric name和description。
例如:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
该处理程序促进了agent与插件之间的通信。
1。导入container包:
2。在run()
函数中添加代码以create并设置处理程序:
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
}
数据收集通过Exporter接口完成,该接口描述了Export
方法:
func Export(
key string, // The item key to collect.
params []string, // Arguments passed to the item key (`myip[arg1, arg2]`).
context ContextProvider // Metadata about the item key data collection.
) (any, error)
import ( "io" "net/http" )
2. 为myIP
结构体实现Export
方法:
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// The plugin can use different data collection logic based on the `key` parameter.
// This implementation only verifies that the provided `key` is supported.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// The log will get forwarded to the agent 2 log.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Collect the data and return it.
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
}
这应该create当前目录下的可执行文件myip
。
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
替换为步骤 5. 中创建的 myip
路径
配置参数名称中的插件名称(本教程中的_MyIP_)必须与_plugin.RegisterMetrics()_函数中定义的插件名称保持一致。
myip
监控项,请执行run:输出应包含您的主机的外部IP地址,并与此类似:
myip [s|192.0.2.0]
至此,您已为Zabbix agent 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{}
// 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 from the agent is received.
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) {
// The plugin can use different data collection logic based on the `key` parameter.
// This implementation only verifies that the provided `key` is supported.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// The log will get forwarded to the agent 2 log.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Collect the data and return it.
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
}