Built-in plugins

Built-in plugins are located in the plugin directory tree, grouped by meaning, for example plugins/system/uptime/uptime.go.

Implementation steps

A built-in plugin for Zabbix agent 2 is a plugin that is compiled directly into the agent. In order to use it, it is required to have Zabbix sources and to recompile Zabbix agent 2.

The entire plugin building process includes four stages. During the first stage Go code is installed, then Zabbix sources are installed and Go environment is configured, after that plugin support packages are installed, and finally the environment for the installation is prepared, which includes agent recompiling.
See the instructions given below.

Stage 1

  1. At first, create a built-in plugin that implements one metric called myip, which returns the external IP address of the host where the agent is running. It will be done by performing an HTTP request to https://api.ipify.org, which returns the IP address of the client connected.

  2. One more Go package is required: "git.zabbix.com/ap/plugin-support/plugin", which is already available in Zabbix source code, and can be downloaded together with Zabbix agent 2 compilation. All the other required package imports come along with Go.

Stage 2

  1. Then, it is necessary to get Zabbix sources. Here, in this sample, Zabbix version 6.2.2. will be implemented.
git clone https://git.zabbix.com/scm/zbx/zabbix.git --branch 6.2.2 --depth 1 --single-branch zabbix-6.2.2

Any Zabbix version starting from 5.0.0 and higher can be used to extract the sources for Zabbix agent 2. However, it should be noted that the different versions may require different steps of implementation.

  1. A configured Go environment with a currently supported Go version is required for building Zabbix agent 2.
    Now, install Zabbix agent 2:
cd zabbix-6.2.2
       ./bootstrap.sh
       ./configure --enable-agent2 --prefix=$(pwd)
       make -s install

At this step, it is important to make sure that Zabbix agent 2 is compiled as it is (without any changes implemented), because later it will be recompiled again (already with the new changes implemented). Thus, if some errors arose during the further steps, this would assure they were due to the errors in the code, and not due to some missing dependencies.

  1. Now, create a directory for your module and edit the file:
mkdir src/go/plugins/myip
       vi src/go/plugins/myip/myip.go
  1. Then, add the following contents to the file. This is the source code of the plugin. Refer to Stage 3 for further details below:
// This is the source code of plugin Myip. It implements 1 metric
       // called myip, which returns the external IP address of the host where
       // Zabbix agent 2 is running.
       
       package myip
       
       // Packages we will use.
       
       import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
       
       // Plugin must define structure and embed plugin.Base structure.
       type Plugin struct {
           plugin.Base
       }
       
       // Create a new instance of the defined plugin structure
       var impl Plugin
       
       // Plugin must implement one or several plugin interfaces.
       func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) {
           // You may use one of Critf, Errf, Infof, Warningf, Debugf, Tracef functions for logging.
           p.Infof("received request to handle %s key with %d parameters", key, len(params))
       
           // Fetch response from the specified URL, it should be just the IP address.
           resp, err := http.Get("https://api.ipify.org")
           if err != nil {
               // Plugin will return an error response if the request failed
               return nil, err
           }
       
           defer resp.Body.Close()
       
           body, err := ioutil.ReadAll(resp.Body)
           if err != nil {
           // Plugin will return an error response if it failed to read the response
               return nil, err
           }
       
           return string(body), nil
       }
       
       func init() {
           // Register our metric, specifying the plugin and metric details.
           // 1 - a pointer to plugin implementation
           // 2 - plugin name
           // 3 - metric name (item key)
           // 4 - metric description
           //
           // NB! The metric description must end with a period, otherwise the Zabbix agent 2 will return an error and won't start!
           // Metric name (item key) and metric description can be repeated in a loop to register additional metrics.
           plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
       }

Stage 3

  1. Package definition. This is the name of your Go package. All files in the package must have the same name. It implements one metric, called myip, which returns the external IP address of the host where Zabbix agent is running.
package myip
  1. Package import. These are the packages that support the plugin. Following packages are used:
import (
           "fmt"
           "io/ioutil"
           "net/http"
           "git.zabbix.com/ap/plugin-support/plugin/container"
           "git.zabbix.com/ap/plugin-support/plugin"
       )
  1. Plugin structure. A plugin must define the structure and embed the plugin.Base structure. This grants the access to all the functionality of a plugin.
type Plugin struct {
           plugin.Base
       }
       
       var impl Plugin
  1. Plugin Export interface. A plugin must implement one or several plugin interfaces. This is where all the plugin functionality is handled. Currently, the Export interface is implemented.
func (p *Plugin) Export(key string, params []string, ctx plugin.ContextProvider) (result interface{}, err error) {
  1. Logging. Use one of Critf, Errf, Infof, Warningf, Debugf, Tracef logging functions available to plugins, in case you need them. These log messages will appear in the same place where the agent is logging.
p.Infof("received request to handle %s key with %d parameters", key, len(params))
  1. Core logic. Fetches the response from the specified URL and reads it, then returns the IP address as a response and closes the response. In case an error occurs while executing the GET request or while reading the response, the error message is returned instead.
    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. Registering the metric.
    Init function is run when Zabbix agent 2 is started. It provides the plugin name, metrics, and interfaces it implements.
    The first parameter grants access to the plugin structure, and provides information on all the available plugin interfaces.
    The second parameter defines the plugin name, which must be unique and not clash with any other already existing plugin name.
    The third parameter defines the metric name. This is the key used to gather data from the plugin.
    The fourth parameter is the description, which must start with a capital letter and end with a period.

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

func init() {
           plugin.RegisterMetrics(&impl, "Myip", "myip", "Return the external IP address of the host where agent is running.")
       }

The metric description must end with a period, otherwise the agent will not start!

Stage 4

  1. Now, tell the agent that there is a plugin to import. Edit file src/go/plugins/plugins_linux.go, and add your plugin "zabbix.com/plugins/myip" to the end of the existing import list:
import (
           _ "zabbix.com/plugins/log"
           _ "zabbix.com/plugins/systemrun"
           _ "zabbix.com/plugins/zabbix/async"
           _ "zabbix.com/plugins/zabbix/stats"
           _ "zabbix.com/plugins/zabbix/sync"
           _ "zabbix.com/plugins/myip"
       )

Two other suitable plugins are also available:plugins_windows.go and plugins_darwin.go. However, note that Zabbix agent 2 is not currently officially supported on darwin.

  1. Then, recompile the agent again:
make -s install
  1. Finally, request the new metric from the agent:
sbin/zabbix_agent2 -t myip

As a result, the external IP address of your host should be displayed.