package server import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" ) // cacheStats is the read side of the NetBox cache the collector publishes. type cacheStats interface { Hits() int64 Misses() int64 } // metrics holds bootapi's Prometheus instruments, registered on a private // registry so tests can construct isolated servers. type metrics struct { reg *prometheus.Registry httpRequests *prometheus.CounterVec // by endpoint,status renders *prometheus.CounterVec // by kind,result netboxLookups *prometheus.CounterVec // by field,result netboxDuration *prometheus.HistogramVec } func newMetrics(cache cacheStats) *metrics { reg := prometheus.NewRegistry() m := &metrics{ reg: reg, httpRequests: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "bootapi_http_requests_total", Help: "HTTP requests handled, by endpoint and status class.", }, []string{"endpoint", "status"}), renders: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "bootapi_render_total", Help: "Template renders, by kind (kickstart|ipxe) and result (ok|error).", }, []string{"kind", "result"}), netboxLookups: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "bootapi_netbox_lookups_total", Help: "NetBox host resolutions, by field (mac|name) and result (ok|notfound|error).", }, []string{"field", "result"}), netboxDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "bootapi_netbox_lookup_duration_seconds", Help: "Latency of NetBox host resolutions.", Buckets: prometheus.DefBuckets, }, []string{"field"}), } reg.MustRegister(m.httpRequests, m.renders, m.netboxLookups, m.netboxDuration) if cache != nil { reg.MustRegister(newCacheCollector(cache)) } reg.MustRegister( collectors.NewGoCollector(), collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), ) return m } // cacheCollector publishes the NetBox cache hit/miss counters, which live on // the Cache itself (atomic ints) rather than in a CounterVec. type cacheCollector struct { stats cacheStats hits *prometheus.Desc miss *prometheus.Desc } func newCacheCollector(s cacheStats) *cacheCollector { return &cacheCollector{ stats: s, hits: prometheus.NewDesc("bootapi_netbox_cache_hits_total", "NetBox cache hits.", nil, nil), miss: prometheus.NewDesc("bootapi_netbox_cache_misses_total", "NetBox cache misses.", nil, nil), } } func (c *cacheCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.hits ch <- c.miss } func (c *cacheCollector) Collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(c.hits, prometheus.CounterValue, float64(c.stats.Hits())) ch <- prometheus.MustNewConstMetric(c.miss, prometheus.CounterValue, float64(c.stats.Misses())) }