zabbix_sender

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 17 Imported by: 0

README

zabbix-sender

Golang package, implementing zabbix sender protocol for sending metrics to zabbix. Supports modern Zabbix 7.0+ proxy group redirect and multi-host high availability.

✨ Features

  • Send data on single host (Zabbix server or Proxy)
  • Send data on multiple hosts in HA (like Zabbix Agent ServerActive)
  • Proxy group redirects (Zabbix 7.0+)
  • Active agent emulation
  • Trapper items
  • Host autoregistration
  • Primary host caching (remembers working proxy)
  • Configurable timeouts & redirect limits
  • Goroutine-safe: one sender, unlimited concurrent sends

📦 Installation

go get github.com/christos-diamantis/zabbix_sender/v2

🚀 Quick Start

package main

import (
    "fmt"
    "time"

    zabbix_sender "github.com/christos-diamantis/zabbix_sender/v2"
)

func main() {
    // Single host
    sender := zabbix_sender.NewSender("zabbix-proxy:10051")

    // Multiple hosts in HA
    senderHA := zabbix_sender.NewSenderHosts([]string{"zabbix-proxy1:10051", "zabbix-proxy2:10051", "zabbix-proxy3"})

    // Create multiple metrics to send as batch
    var metrics []*zabbix_sender.Metric
    metrics = append(metrics, zabbix_sender.NewMetric("localhost", "cpu", "1.22", true, time.Now())) // Emulating Zabbix agent (active agent items) and specifying timestamp
    metrics = append(metrics, zabbix_sender.NewMetric("localhost", "status", "OK", true)) // Emulating Zabbix agent (active agent items)
    metrics = append(metrics, zabbix_sender.NewMetric("localhost", "someTrapper", "3.14", false)) // Sending on trapper item type

    // Send the metrics on the single host
    resActive, errActive, resTrapper, errTrapper := sender.SendMetrics(metrics)

    // Print the results of sending to single host
    fmt.Printf("Agent active, response=%s, info=%s, error=%v\n", resActive.Response, resActive.Info, errActive)
    fmt.Printf("Trapper, response=%s, info=%s, error=%v\n", resTrapper.Response, resTrapper.Info, errTrapper)

    // Send the metrics on the list of hosts
    resActiveHA, errActiveHA, resTrapperHA, errTrapperHA := senderHA.SendMetrics(metrics)

    // Print the results of sending to list of hosts
    fmt.Printf("Agent active, response=%s, info=%s, error=%v\n", resActiveHA.Response, resActiveHA.Info, errActiveHA)
    fmt.Printf("Trapper, response=%s, info=%s, error=%v\n", resTrapperHA.Response, resTrapperHA.Info, errTrapperHA)

}

📖 All Usage Examples

  1. Single Host
sender := zabbix_sender.NewSender("my-zabbix-proxy:10051")
  1. Multiple Hosts
hosts := []string{
    "my-zabbix-proxy1:10051",
    "my-zabbix-proxy2:10051",
    "my-zabbix-proxy3",
}
sender := zabbix_sender.NewSenderHosts(hosts)
sender.MaxRedirects = 3
sender.UpdateHost = true // cache final redirected proxy

Behavior: Tries cached PrimaryHost first -> falls back to list order -> caches first successful host.

  1. Active Agent emulation
// Emulate Zabbix Agent active checks
metrics := []*zabbix_sender.Metric{
    zabbix_sender.NewMetric("MyAgent", "agent.ping", "1", true),           // active=true
    zabbix_sender.NewMetric("MyAgent", "agent.version", "2.4", true),      // active=true
    zabbix_sender.NewMetric("MyAgent", "system.cpu.util", "15.2", true),   // active=true
}
resActive, _, _, _ := sender.SendMetrics(metrics) // uses "agent data" protocol
  1. Trapper Items
// Custom trapper items
metrics := []*zabbix_sender.Metric{
    zabbix_sender.NewMetric("AppServer", "app.metrics.custom", "123", false), // trapper=false
    zabbix_sender.NewMetric("Database", "db.connections", "47", false),
}
_, errTrapper, _, _ := sender.SendMetrics(metrics) // uses "sender data" protocol
  1. Mixed Active + Trapper
metrics := []*zabbix_sender.Metric{
    zabbix_sender.NewMetric("Host", "agent.ping", "1", true),    // → active packet
    zabbix_sender.NewMetric("Host", "custom.metric", "42", false), // → trapper packet
}

resActive, errActive, resTrapper, errTrapper := sender.SendMetrics(metrics)
// resActive = agent data response
// resTrapper = sender data response  
  1. Host autoregistration
err := sender.RegisterHost("NewHost", "Linux mysql nginx version 1.18")
if err != nil {
    log.Fatal(err)
}
  1. Custom timeouts
sender := zabbix_sender.NewSenderTimeout(
    "proxy:10051",
    10*time.Second,  // connect
    30*time.Second,  // read  
    10*time.Second,  // write
)
  1. Parse response statistics
info, err := resActive.GetInfo()
if err == nil {
    fmt.Printf("Processed: %d, Failed: %d, Total: %d (%.3fs)\n",
        info.Processed, info.Failed, info.Total, info.Spent.Seconds())
}
  1. TLS (certificate-based, like TLSConnect=cert)
tlsConfig, err := zabbix_sender.TLSConfigFromFiles(
    "/etc/zabbix/ca.pem",     // TLSCAFile ("" = system CAs)
    "/etc/zabbix/cert.pem",   // TLSCertFile ("" = no client cert)
    "/etc/zabbix/key.pem",    // TLSKeyFile
)
if err != nil {
    log.Fatal(err)
}

sender := zabbix_sender.NewSender("zabbix-server:10051")
sender.TLSConfig = tlsConfig
sender.SourceIP = "192.0.2.10" // optional, like Zabbix SourceIP

TLS-PSK is not implemented by Go's crypto/tls. If you need PSK, plug your own transport (e.g. an OpenSSL-backed dialer) via the hook that replaces the built-in dialer:

sender.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {
    return myPSKDialer.DialContext(ctx, network, addr)
}
  1. From a Zabbix agent configuration file
// Reads ServerActive (fallback Server), Hostname, SourceIP and TLS* keys.
// One Sender per comma-separated ServerActive destination; semicolon-
// separated addresses are HA nodes within a destination.
senders, err := zabbix_sender.NewSenderFromConfig("/etc/zabbix/zabbix_agentd.conf")
if err != nil {
    log.Fatal(err)
}
for _, s := range senders { // every destination gets a full copy
    s.SendMetrics(metrics)
}

// Or inspect the parsed values yourself:
cfg, _ := zabbix_sender.ParseAgentConfig("/etc/zabbix/zabbix_agentd.conf")
fmt.Println(cfg.ServerActive, cfg.Hostname, cfg.SourceIP, cfg.TLS)
  1. Context support
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
resActive, errActive, resTrapper, errTrapper := sender.SendMetricsContext(ctx, metrics)

🔧 Advanced Configuration

sender := zabbix_sender.NewSenderHosts(hosts)
sender.MaxRedirects = 10      // handle complex proxy groups
sender.UpdateHost = true      // permanently cache final proxy
sender.SetPrimaryHost("known-good-proxy:10051") // pre-set cached host

A Sender is safe for concurrent use: call SendMetrics/Send from as many goroutines as you like. Set the configuration fields (Hosts, MaxRedirects, timeouts, ...) before sharing the sender between goroutines.

cached := sender.PrimaryHost() // read the cached working host

🛠️ Compatibility

  • Zabbix: 4.0+ (redirects: 7.0+)

  • Go: 1.20+

🙏 Credits

Forked & enhanced from chmller/go-zabbix-sender.

📄 License

MIT License - see LICENSE file

Star this repo if it helps your Zabbix setup!

Documentation

Overview

Package zabbix_sender implements Zabbix sender protocol with proxy group redirects and multi-host HA support.

Index

Constants

View Source
const DefaultChunkSize = 250

DefaultChunkSize is the number of metrics sent per packet when Sender.ChunkSize is 0 (same default as python-zabbix-utils).

View Source
const DefaultMaxResponseSize = 16 << 20 // 16 MiB

DefaultMaxResponseSize caps how large a response body the sender accepts when Sender.MaxResponseSize is 0. Real Zabbix answers are tiny; the cap only guards against a broken or malicious peer.

Variables

This section is empty.

Functions

func TLSConfigFromFiles

func TLSConfigFromFiles(caFile, certFile, keyFile string) (*tls.Config, error)

TLSConfigFromFiles builds a certificate-based tls.Config the way zabbix_sender does for TLSConnect=cert:

  • caFile (TLSCAFile) is the CA bundle used to verify the server; empty means the system CA pool.
  • certFile/keyFile (TLSCertFile/TLSKeyFile) are the client certificate and key; both empty means no client certificate is presented.

The result can be assigned to Sender.TLSConfig, possibly after further adjustment (e.g. ServerName when connecting by IP).

Types

type AgentConfig

type AgentConfig struct {
	// ServerActive holds the parsed ServerActive value: one entry per
	// independent destination (comma-separated in the config file), each
	// entry a list of HA nodes (semicolon-separated) with ports
	// normalized. Every destination is meant to receive a full copy of
	// the data; within a destination only the first reachable node is.
	ServerActive [][]string

	// Hostname is the agent's Hostname, useful as the default Metric host.
	Hostname string

	// SourceIP is the local address to bind outgoing connections to.
	SourceIP string

	// TLS holds every TLS* key of the config file verbatim, with
	// lowercased key names ("tlsconnect", "tlscafile", "tlscertfile",
	// "tlskeyfile", "tlspskfile", "tlspskidentity", ...).
	TLS map[string]string
}

AgentConfig holds the sender-relevant values of a zabbix_agentd.conf / zabbix_agent2.conf file.

func ParseAgentConfig

func ParseAgentConfig(path string) (*AgentConfig, error)

ParseAgentConfig reads a Zabbix agent configuration file (flat Key=Value lines, # comments). It extracts ServerActive (falling back to Server, then to 127.0.0.1:10051), Hostname, SourceIP, and all TLS* keys. Keys are matched case-insensitively; Include directives are not followed.

func (*AgentConfig) TLSClientConfig

func (c *AgentConfig) TLSClientConfig() (*tls.Config, error)

TLSClientConfig builds a tls.Config from the config file's TLS* keys. It returns (nil, nil) when TLSConnect is absent or "unencrypted", a certificate-based config for TLSConnect=cert, and an error for TLSConnect=psk: Go's crypto/tls has no TLS-PSK support, use Sender.DialFunc with a PSK-capable transport instead.

type ClusterResult

type ClusterResult struct {
	Sender     *Sender
	ResActive  Response
	ErrActive  error
	ResTrapper Response
	ErrTrapper error
}

ClusterResult is the outcome of one destination's send.

func (*ClusterResult) Err

func (r *ClusterResult) Err() error

Err returns the first non-nil error of the result.

type Metric

type Metric struct {
	Host   string `json:"host"`
	Key    string `json:"key"`
	Value  string `json:"value"`
	Clock  int64  `json:"clock,omitempty"`
	NS     int    `json:"ns,omitempty"`
	Active bool   `json:"-"`
}

Metric represents a Zabbix metric.

func NewMetric

func NewMetric(host, key, value string, agentActive bool, t ...time.Time) *Metric

NewMetric creates a Zabbix metric.

agentActive=true for active agent items ("agent data"), agentActive=false for trapper items ("sender data"). t optionally sets custom timestamp.

func NewMetricValue

func NewMetricValue(host, key string, value interface{}, agentActive bool, t ...time.Time) *Metric

NewMetricValue is NewMetric for values of any type: numbers, booleans, fmt.Stringer implementations, etc. are formatted with fmt.Sprint (the Zabbix protocol carries all values as strings).

type MultiSender

type MultiSender struct {
	Senders []*Sender
}

MultiSender fans metrics out to multiple independent destinations, each a Sender with its own HA node list — the Zabbix agent semantics for comma-separated ServerActive entries: every destination receives a full copy of the data.

func NewMultiSender

func NewMultiSender(clusters [][]string) *MultiSender

NewMultiSender creates a MultiSender from destination clusters, each a list of HA nodes (ports normalized, IPv6 supported).

func NewMultiSenderFromConfig

func NewMultiSenderFromConfig(path string) (*MultiSender, error)

NewMultiSenderFromConfig creates a MultiSender from a Zabbix agent configuration file (see NewSenderFromConfig).

func (*MultiSender) SendMetrics

func (m *MultiSender) SendMetrics(metrics []*Metric) []ClusterResult

SendMetrics sends the metrics to every destination concurrently and returns one result per destination, in Senders order.

func (*MultiSender) SendMetricsContext

func (m *MultiSender) SendMetricsContext(ctx context.Context, metrics []*Metric) []ClusterResult

SendMetricsContext is SendMetrics honoring the context's deadline and cancellation on top of each Sender's own timeouts.

type Packet

type Packet struct {
	Request      string    `json:"request"`
	Data         []*Metric `json:"data,omitempty"`
	Clock        int64     `json:"clock,omitempty"`
	NS           int       `json:"ns,omitempty"`
	Host         string    `json:"host,omitempty"`
	HostMetadata string    `json:"host_metadata,omitempty"`
}

Packet struct.

func NewPacket

func NewPacket(data []*Metric, agentActive bool, t ...time.Time) *Packet

NewPacket returns a zabbix packet with a list of metrics

func (*Packet) DataLen

func (p *Packet) DataLen() []byte

DataLen Packet class method, return 8 bytes with packet length in little endian order

type RedirectInfo

type RedirectInfo struct {
	Revision int    `json:"revision"`
	Address  string `json:"address"`
}

RedirectInfo struct.

type Response

type Response struct {
	Response string        `json:"response"`
	Info     string        `json:"info"`
	Redirect *RedirectInfo `json:"redirect,omitempty"`
}

Response is the response struct from Zabbix server/proxy.

func (*Response) GetInfo

func (r *Response) GetInfo() (*ResponseInfo, error)

GetInfo parses success response "info" field into statistics.

type ResponseError

type ResponseError struct {
	Host string
	Res  Response
}

ResponseError is returned when a server/proxy was reached and answered with a well-formed non-success response. It lets callers distinguish application-level failures from transport errors; Send does not fail over to another host when it occurs.

func (*ResponseError) Error

func (e *ResponseError) Error() string

type ResponseInfo

type ResponseInfo struct {
	Processed int
	Failed    int
	Total     int
	Spent     time.Duration
}

ResponseInfo struct holds parsed statistics from response "info" field.

type Sender

type Sender struct {
	Hosts          []string // ordered list of proxies/servers; first successful cached as primary host
	MaxRedirects   int      // max redirect attempts before error; default is 3
	UpdateHost     bool     // if true, cache the final redirect target instead of the starting host
	ConnectTimeout time.Duration
	ReadTimeout    time.Duration
	WriteTimeout   time.Duration

	// MaxResponseSize caps the response body length the sender accepts.
	// 0 means DefaultMaxResponseSize.
	MaxResponseSize uint64

	// ChunkSize splits packets with more than this many metrics into
	// multiple sequential packets; the returned Response carries the
	// summed statistics. 0 means DefaultChunkSize, negative disables
	// chunking.
	ChunkSize int

	// Compression zlib-compresses outgoing packets (protocol flag 0x02).
	// Compressed responses are always accepted, regardless of this flag.
	Compression bool

	// TLSConfig enables certificate-based TLS (Zabbix TLSConnect=cert)
	// when non-nil. Ignored when DialFunc is set.
	TLSConfig *tls.Config

	// SourceIP optionally binds outgoing connections to a local address
	// (Zabbix SourceIP). Ignored when DialFunc is set.
	SourceIP string

	// DialFunc, when non-nil, replaces the built-in dialer entirely and
	// its net.Conn is used as the packet transport. This is the hook for
	// TLS-PSK (not supported by crypto/tls) or any custom transport; the
	// implementation should honor ctx and ConnectTimeout itself.
	DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
	// contains filtered or unexported fields
}

Sender sends packets to a Zabbix server/proxy.

A Sender is safe for concurrent use by multiple goroutines: sends run in parallel, and the working-host cache is internally synchronized. The configuration fields (Hosts, MaxRedirects, timeouts, ...) are read without locking and must be set before the Sender is shared between goroutines.

func NewSender

func NewSender(host string) *Sender

NewSender creates sender for single host.

func NewSenderFromConfig

func NewSenderFromConfig(path string) ([]*Sender, error)

NewSenderFromConfig creates one Sender per ServerActive destination of a Zabbix agent configuration file, with SourceIP and certificate-based TLS applied. Every returned Sender is meant to receive a full copy of the data (Zabbix agent semantics for comma-separated ServerActive entries).

func NewSenderHosts

func NewSenderHosts(hosts []string) *Sender

NewSenderHosts creates sender for multiple hosts (HA or Proxy Group).

func NewSenderTimeout

func NewSenderTimeout(
	host string,
	connectTimeout time.Duration,
	readTimeout time.Duration,
	writeTimeout time.Duration,
) *Sender

NewSenderTimeout creates Sender with custom timeouts.

func (*Sender) PrimaryHost

func (s *Sender) PrimaryHost() string

PrimaryHost returns the cached working host (empty = none cached yet).

func (*Sender) RegisterHost

func (s *Sender) RegisterHost(host, hostmetadata string) error

RegisterHost sends host autoregistration request ("active checks"). A first "failed" answer is expected for unknown hosts (it is what triggers the server-side autoregistration), so it retries once to confirm.

func (*Sender) RegisterHostContext

func (s *Sender) RegisterHostContext(ctx context.Context, host, hostmetadata string) error

RegisterHostContext is RegisterHost honoring the context's deadline and cancellation on top of the Sender's own timeouts.

func (*Sender) Send

func (s *Sender) Send(packet *Packet) (Response, error)

Send sends single packet with redirect/HA handling. Caches working PrimaryHost for future calls. Fails over to the next host only on transport errors; a host that answers (even with "failed") is considered reachable and its answer final (see ResponseError).

func (*Sender) SendContext

func (s *Sender) SendContext(ctx context.Context, packet *Packet) (Response, error)

SendContext is Send honoring the context's deadline and cancellation on top of the Sender's own timeouts.

func (*Sender) SendMetrics

func (s *Sender) SendMetrics(metrics []*Metric) (resActive Response, errActive error, resTrapper Response, errTrapper error)

SendMetrics sends mixed active+trapper metrics. Automatically separates into "agent data" and "sender data" packets. Returns 4 values: (activeRes, activeErr, trapperRes, trapperErr)

func (*Sender) SendMetricsContext

func (s *Sender) SendMetricsContext(ctx context.Context, metrics []*Metric) (resActive Response, errActive error, resTrapper Response, errTrapper error)

SendMetricsContext is SendMetrics honoring the context's deadline and cancellation on top of the Sender's own timeouts.

func (*Sender) SendValue

func (s *Sender) SendValue(host, key string, value interface{}) (Response, error)

SendValue sends one trapper value in a single call, formatting value with fmt.Sprint (like python-zabbix-utils' send_value).

func (*Sender) SendValueContext

func (s *Sender) SendValueContext(ctx context.Context, host, key string, value interface{}) (Response, error)

SendValueContext is SendValue honoring the context's deadline and cancellation on top of the Sender's own timeouts.

func (*Sender) SetPrimaryHost

func (s *Sender) SetPrimaryHost(host string)

SetPrimaryHost pre-sets (or, with "", clears) the cached working host.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL