diff --git a/Makefile b/Makefile index 0da99af..3904394 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ FRONTEND_WEB_SRC := $(shell find cmd/frontend/web/src -type f 2>/dev/null) \ FRONTEND_WEB_DIST := cmd/frontend/web/dist/index.html NATIVE_ARCH := $(shell go env GOARCH) -VERSION := 1.1.1 +VERSION := 1.1.2 COMMIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X '$(MODULE)/cmd.version=$(VERSION)' \ diff --git a/cmd/server/main.go b/cmd/server/main.go index 0a354fa..5487efc 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -150,7 +150,7 @@ func run() error { if vppClient != nil { vppSrc = vppClient } - metrics.Register(reg, chkr, vppSrc) + metrics.Register(reg, chkr, vppSrc, cfg.SourceTag) reg.MustRegister(grpcMetrics) mux := http.NewServeMux() diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 19f4ec3..5871ca0 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -378,10 +378,9 @@ func (c *Checker) GetBackendInfo(name string) (metrics.BackendInfo, bool) { return metrics.BackendInfo{}, false } return metrics.BackendInfo{ - Health: w.backend, - Enabled: w.entry.Enabled, - HCName: w.entry.HealthCheck, - SourceTag: w.entry.SourceTag, + Health: w.backend, + Enabled: w.entry.Enabled, + HCName: w.entry.HealthCheck, }, true } diff --git a/internal/config/config.go b/internal/config/config.go index 19a0b3b..fb4f05a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -17,6 +17,7 @@ import ( // Config is the top-level parsed and validated configuration. type Config struct { + SourceTag string // this node's nginx source tag; defaults to the short hostname HealthChecker HealthCheckerConfig VPP VPPConfig HealthChecks map[string]HealthCheck @@ -123,7 +124,6 @@ type TCPParams struct { type Backend struct { Address net.IP HealthCheck string // name reference into Config.HealthChecks; "" = no probing, assume healthy - SourceTag string // nginx source tag; defaults to the backend name if omitted from config Enabled bool // default true; false = exclude from serving entirely } @@ -164,6 +164,7 @@ type rawConfig struct { } type rawMaglev struct { + SourceTag string `yaml:"source-tag"` HealthChecker rawHealthCheckerCfg `yaml:"healthchecker"` VPP rawVPPCfg `yaml:"vpp"` HealthChecks map[string]rawHealthCheck `yaml:"healthchecks"` @@ -219,8 +220,7 @@ type rawParams struct { type rawBackend struct { Address string `yaml:"address"` HealthCheck string `yaml:"healthcheck"` - SourceTag string `yaml:"source-tag"` // defaults to backend name if omitted - Enabled *bool `yaml:"enabled"` // nil → default true + Enabled *bool `yaml:"enabled"` // nil → default true } type rawPoolBackend struct { @@ -301,6 +301,18 @@ func parse(data []byte) (*Config, error) { func convert(r *rawMaglev) (*Config, error) { cfg := &Config{} + // ---- source-tag ----------------------------------------------------------- + cfg.SourceTag = r.SourceTag + if cfg.SourceTag == "" { + if h, err := os.Hostname(); err == nil { + if dot := strings.IndexByte(h, '.'); dot > 0 { + cfg.SourceTag = h[:dot] + } else { + cfg.SourceTag = h + } + } + } + // ---- healthchecker -------------------------------------------------------- cfg.HealthChecker.Netns = r.HealthChecker.Netns cfg.HealthChecker.TransitionHistory = r.HealthChecker.TransitionHistory @@ -590,14 +602,9 @@ func convertBackend(name string, r *rawBackend, hcs map[string]HealthCheck) (Bac return Backend{}, fmt.Errorf("invalid address %q", r.Address) } - sourceTag := r.SourceTag - if sourceTag == "" { - sourceTag = name - } b := Backend{ Address: ip, HealthCheck: r.HealthCheck, - SourceTag: sourceTag, Enabled: boolDefault(r.Enabled, true), } diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 7f22579..df4bd5b 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -21,10 +21,9 @@ import ( // BackendInfo holds the health and config state needed by the collector. type BackendInfo struct { - Health *health.Backend - Enabled bool - HCName string // healthcheck name from config - SourceTag string // nginx source tag; equals backend name when unset in config + Health *health.Backend + Enabled bool + HCName string // healthcheck name from config } // StateSource provides read-only access to the running checker state. @@ -132,10 +131,11 @@ var ( // on each scrape. This avoids stale label sets when backends are added or // removed by a config reload. type Collector struct { - src StateSource - vpp VPPSource // optional; nil when VPP integration is disabled + src StateSource + vpp VPPSource // optional; nil when VPP integration is disabled + sourceTag string - backendInfo *prometheus.Desc + maglevInfo *prometheus.Desc backendState *prometheus.Desc backendHealth *prometheus.Desc backendEnabled *prometheus.Desc @@ -154,14 +154,15 @@ type Collector struct { // NewCollector creates a Collector backed by the given StateSource. vpp may // be nil when VPP integration is disabled; in that case vpp_* metrics are // simply not emitted. -func NewCollector(src StateSource, vpp VPPSource) *Collector { +func NewCollector(src StateSource, vpp VPPSource, sourceTag string) *Collector { return &Collector{ - src: src, - vpp: vpp, - backendInfo: prometheus.NewDesc( - "maglev_backend_info", - "Static backend metadata. Always 1; metadata is conveyed via labels.", - []string{"backend", "address", "healthcheck", "source_tag"}, nil, + src: src, + vpp: vpp, + sourceTag: sourceTag, + maglevInfo: prometheus.NewDesc( + "maglev_info", + "Static maglevd instance metadata. Always 1; metadata is conveyed via labels.", + []string{"source_tag"}, nil, ), backendState: prometheus.NewDesc( "maglev_backend_state", @@ -223,7 +224,7 @@ func NewCollector(src StateSource, vpp VPPSource) *Collector { // Describe implements prometheus.Collector. func (c *Collector) Describe(ch chan<- *prometheus.Desc) { - ch <- c.backendInfo + ch <- c.maglevInfo ch <- c.backendState ch <- c.backendHealth ch <- c.backendEnabled @@ -239,6 +240,8 @@ func (c *Collector) Describe(ch chan<- *prometheus.Desc) { // Collect implements prometheus.Collector. func (c *Collector) Collect(ch chan<- prometheus.Metric) { + ch <- prometheus.MustNewConstMetric(c.maglevInfo, prometheus.GaugeValue, 1.0, c.sourceTag) + states := []health.State{ health.StateUnknown, health.StateUp, @@ -255,11 +258,6 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) { } addr := info.Health.Address.String() - ch <- prometheus.MustNewConstMetric( - c.backendInfo, prometheus.GaugeValue, 1.0, - name, addr, info.HCName, info.SourceTag, - ) - // One time-series per possible state; the current state is 1, rest 0. for _, s := range states { val := 0.0 @@ -356,8 +354,8 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) { // Register registers all metrics with the given registry. vpp may be nil // to disable VPP-related metrics. -func Register(reg prometheus.Registerer, src StateSource, vpp VPPSource) *Collector { - coll := NewCollector(src, vpp) +func Register(reg prometheus.Registerer, src StateSource, vpp VPPSource, sourceTag string) *Collector { + coll := NewCollector(src, vpp, sourceTag) reg.MustRegister(coll) reg.MustRegister(ProbeTotal) reg.MustRegister(ProbeDuration)