Criando um plugin
Esta página destina-se àqueles que têm interesse em desenvolver seu próprio plugin (coletor de dados independente) para o Zabbix agent 2.
Um plugin personalizado permite estender a funcionalidade do Zabbix agent 2 além dos plugins integrados e dos plugins carregáveis fornecidos.
Cada plugin é um pacote Go que define a estrutura e implementa uma ou várias interfaces (Exporter, Configurator, Runner). Para mais informações, consulte Interfaces de plugin e Diagrama de conexão.
Este guia ajudará você a criar um plugin carregável personalizado.
Para orientações adicionais, consulte também o repositório de:
O que você criará
Este é um tutorial passo a passo para criar um plugin carregável simples chamado MyIP.
Este plugin implementará uma única chave de item (myip) que retorna o endereço IP externo do host do agent Zabbix.
Etapa 1: Configuração
- Um plugin é um módulo Go padrão.
Comece inicializando o arquivo
go.modno diretório do plugin para rastrear as dependências do plugin:
cd path/to/plugins/myip # Mude para o diretório do seu plugin
go mod init myip
- Instale a dependência obrigatória Zabbix Go SDK (
golang.zabbix.com/sdk):
go get golang.zabbix.com/sdk@$LATEST_COMMIT_HASH
Substitua $LATEST_COMMIT_HASH pelo hash do commit HEAD mais recente do repositório golang.zabbix.com/sdk no branch de release apropriado.
Por exemplo:
go get golang.zabbix.com/sdk@af85407
Observe que o versionamento de golang.zabbix.com/sdk atualmente não é suportado, mas isso pode mudar no futuro.
Dependências adicionais podem ser instaladas conforme necessário usando go get.
- Crie um arquivo
main.govazio para o código-fonte do plugin:
touch main.go
Agora a configuração inicial está concluída, e o plugin está pronto para desenvolvimento.
Etapa 2: Estrutura do plugin
O módulo golang.zabbix.com/sdk, instalado na etapa anterior, fornece a estrutura necessária para o desenvolvimento de plugins e garante que todos os plugins tenham uma estrutura consistente.
- Configure o fluxo básico de execução.
Comece definindo o fluxo principal de execução do plugin. Adicione o seguinte código a main.go:
package main
func main() {
err := run()
if err != nil {
panic(err)
}
}
func run() error {
return nil
}
Isso estabelece o fluxo básico de execução do plugin. A função run conterá posteriormente a lógica principal do plugin.
- Explore as interfaces do plugin.
Um plugin do Zabbix agent 2 deve ser representado por uma struct que implemente interfaces do pacote golang.zabbix.com/sdk/plugin:
- Accessor - define métodos essenciais que todos os plugins devem implementar, como definir o nome do plugin e lidar com timeouts de chave de item.
- Uma ou mais das seguintes interfaces funcionais de plugin:
- Exporter - executa uma coleta e retorna um valor (ou valores), nada ou um erro; frequentemente usado em conjunto com a interface Collector.
- Collector - gerencia a coleta periódica de dados.
- Runner - define os procedimentos de inicialização e encerramento do plugin.
- Watcher - permite implementar a coleta independente de métricas, contornando o agendador interno do agent; útil para monitoramento baseado em traps ou orientado a eventos.
- Configurator - define como o plugin lê e aplica suas configurações.
Você pode implementar essas interfaces por conta própria ou usar as implementações padrão fornecidas pelo Zabbix Go SDK, modificando-as conforme necessário. Este tutorial usa as implementações padrão.
- Crie a struct do plugin.
Agora, importe o pacote plugin e crie uma struct myIP que incorpora a struct plugin.Base:
import "golang.zabbix.com/sdk/plugin"
type myIP struct {
plugin.Base
}
No momento, a struct myIP satisfaz a interface Accessor.
Um método para implementar uma das interfaces funcionais de plugin, Exporter, será adicionado posteriormente no tutorial.
Etapa 3: Definir chaves de item
Seu plugin precisa das chaves de item para coletar dados e fornecê-los ao Zabbix server ou proxy.
- Importe o pacote errs para tratamento de erros:
import "golang.zabbix.com/sdk/errs"
- Registre as chaves de item usando a função
plugin.RegisterMetrics()dentro da funçãorun():
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
}
Para registrar várias chaves de item, repita os parâmetros nome da métrica e descrição para cada métrica.
Por exemplo:
plugin.RegisterMetrics(&impl, "Myip", "metric.one", "Metric one description.", "metric.two", "Metric two description.")
Etapa 4: Configurar o handler
O handler facilita a comunicação entre o agent e o plugin.
- Importe o pacote container:
import "golang.zabbix.com/sdk/plugin/container"
- Dentro da função
run(), adicione código para criar e configurar um handler:
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
}
Etapa 5: Implementar a coleta de dados
A coleta de dados é feita por meio da interface Exporter, que descreve o método Export:
func Export(
key string, // A chave do item a ser coletado.
params []string, // Argumentos passados para a chave do item (`myip[arg1, arg2]`).
context ContextProvider // Metadados sobre a coleta de dados da chave do item.
) (any, error)
- Importe os pacotes necessários para requisições HTTP e leitura da resposta:
import (
"io"
"net/http"
)
- Implemente o método
Exportpara a structmyIP:
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// O plugin pode usar diferentes lógicas de coleta de dados com base no parâmetro `key`.
// Esta implementação apenas verifica se a `key` fornecida é suportada.
if key != "myip" {
return nil, errs.Errorf("unknown item key %q", key)
}
// O log será encaminhado para o log do agent 2.
p.Infof(
"received request to handle %q key with %d parameters",
key,
len(params),
)
// Coleta os dados e os retorna.
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
}
Etapa 6: Compilar e configurar o plugin
- Para compilar o plugin, execute:
go mod tidy
go build
Isso deve criar um executável myip no diretório atual.
- Configure o Zabbix agent 2 para usar o plugin:
echo "Plugins.MyIP.System.Path=$PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE" > /etc/zabbix_agent2.d/plugins.d/myip.conf
Substitua $PATH_TO_THE_MYIP_PLUGIN_EXECUTABLE pelo caminho para o myip criado na etapa 5.
O nome do plugin no nome do parâmetro de configuração (MyIP neste tutorial) deve corresponder ao nome do plugin definido na função plugin.RegisterMetrics().
- Para testar o plugin e seu item
myip, execute:
zabbix_agent2 -c /etc/zabbix_agent2.conf -t myip
A saída deve conter um endereço IP externo do seu host e ser semelhante a isto:
myip [s|192.0.2.0]
Com isso, você criou um plugin carregável simples para o Zabbix agent 2. Parabéns!
Código-fonte completo
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{}
// Registra a chave de item `myip`.
err := plugin.RegisterMetrics(
p,
"MyIP", // Nome do plugin
"myip", // Nome da chave de item
"Retorna o endereço IP do host.", // Descrição da chave de item
)
if err != nil {
return errs.Wrap(err, "falha ao registrar métricas")
}
// Cria um novo handler.
h, err := container.NewHandler("MyIP") // Nome do plugin
if err != nil {
return errs.Wrap(err, "falha ao criar novo handler")
}
// Configura o log para encaminhar logs do plugin para o agent.
// Disponível via p.Logger.Infof, p.Logger.Debugf etc.
p.Logger = h
// Inicia a execução do plugin.
// Bloqueia até que uma solicitação de encerramento do agent seja recebida.
err = h.Execute()
if err != nil {
return errs.Wrap(err, "falha ao executar o handler do plugin")
}
return nil
}
func (p *myIP) Export(
key string, params []string, context plugin.ContextProvider,
) (any, error) {
// O plugin pode usar diferentes lógicas de coleta de dados com base no parâmetro `key`.
// Esta implementação apenas verifica se a `key` fornecida é suportada.
if key != "myip" {
return nil, errs.Errorf("chave de item desconhecida %q", key)
}
// O log será encaminhado para o log 2 do agent.
p.Infof(
"solicitação recebida para processar a chave %q com %d parâmetros",
key,
len(params),
)
// Coleta os dados e os retorna.
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, errs.Wrap(err, "falha ao obter o endereço IP")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errs.Wrap(err, "falha ao ler o corpo da resposta")
}
return string(body), nil
}