这是原厂英文文档的翻译页面. 欢迎帮助我们 完善文档.

Build a plugin (tutorial)

This is a step-by-step tutorial to create a simple loadable plugin for Zabbix agent 2.

What you'll build

During this tutorial, you will add a new loadable plugin "MyIP". The plugin will implement 1 metric called myip, which returns the external IP address of the host where Zabbix agent 2 is running.

Part 1: Writing the Go code

In this section you will learn how to write the plugin that adds a new metric to Zabbix agent 2.

  1. Create a new directory myip in /usr/local/zabbix/go/plugins/.

  2. Create the file main.go inside myip directory and define the name of your Go package.

Keep the file open to add more lines as described in the next steps.

/usr/local/zabbix/go/plugins/myip/main.go

package main
  1. Specify the packages to import. These are the packages that support the plugin.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
  1. Define the plugin structure.
    Embed the plugin.Base structure to gain access to the standard plugin functionality.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
  1. Implement plugin interface Export. The export interface performs a poll and returns a value.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
       
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error)
  1. Add logging.
    The log messages will appear in the Zabbix agent 2 log. You can use one of the logging functions available to plugins: Critf, Errf, Infof, Warningf, Debugf, Tracef.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
       
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
       }
  1. Implement the core plugin logic. This logic fetches the response from the specified URL and reads it, then returns the IP address as a response and closes the request. In case of an error when executing the GET request or reading a response, the error is returned instead.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
       
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
  1. Register the metric. Zabbix agent 2 initiates running init() function upon startup. This function will call plugin.RegisterMetrics(structure, plugin name, metric name, description) method to get the plugin data.

The plugin.RegisterMetrics method parameter description:

  • structure - a pointer to plugin implementation; grants access to the plugin structure, including list of available plugin interfaces (for example, &impl).
  • name - plugin name; must be unique (for example, "Myip").
  • metric name - metric name (for example, "myip"). This is the item key used to gather data from a plugin.
  • description - metric description; must start with a capital letter and end with a period (for example, ""Return the external IP address of the host where agent is running.").

The third and fourth parameters can be repeated multiple times in a row to register multiple metrics.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
       
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
       
       func init() {
                  plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
              }
  1. Define the main function, which will implement Zabbix plugin handler to create and start the plugin. Defining the main() function is mandatory.

/usr/local/zabbix/go/plugins/myip/main.go

package main
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       type Plugin struct {
                  plugin.Base
              }
              
              var impl Plugin
       
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error){
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               return nil, err
           }
              
           defer resp.Body.Close()
              
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
               return nil, err
           }
              
           return string(body), nil    
       }
       
       func init() {
                  plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
              }
       
       func main() {
                  h, err := container.NewHandler(impl.Name())
                  if err != nil {
                      panic(fmt.Sprintf("failed to create plugin handler %s", err.Error()))
                  }
                  impl.Logger = &h
              
                  err = h.Execute()
                  if err != nil {
                      panic(fmt.Sprintf("failed to execute plugin handler %s", err.Error()))
                  }
              }

Part 2: building the plugin

  1. Execute this bash script to create go files for dependency handling, and to download the dependencies automatically:
go mod init myip
       GOPROXY=direct go mod tidy
       go build

You should receive an output similar to this:

go: creating new go.mod: module myip
       go: to add module requirements and sums:
           go mod tidy
       go: finding module for package git.zabbix.com/ap/plugin-support/plugin/container
       go: finding module for package git.zabbix.com/ap/plugin-support/plugin
       go: found git.zabbix.com/ap/plugin-support/plugin in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
       go: found git.zabbix.com/ap/plugin-support/plugin/container in git.zabbix.com/ap/plugin-support v0.0.0-20220608100211-35b8bffd7ad0
  1. Create an executable myip, which is the loadable plugin.

  2. Specify the path to the plugin configuration file in Zabbix agent 2 configuration file. The path should be set in the Plugins.<PluginName>.System.Path parameter. Replace <PluginName> with the name of the plugin, defined in the code when calling plugin.RegisterMetrics() function (for this tutorial, Plugins.Myip.System.Path).

echo 'Plugins.Myip.System.Path=/usr/local/zabbix/go/plugins/myip/myip' > /etc/zabbix_agent2.d/plugins.d/myip.conf
  1. Now, everything is ready to test the metric:
zabbix_agent2 -t myip

The response should contain the external IP address of your host.

In case of an error, first make sure that the user zabbix has permissions to access /usr/local/zabbix/go/plugins/myip directory.