type ClusterManager struct {
Zone string
OOMCountDesc *prometheus.Desc
RAMUsageDesc *prometheus.Desc
// request
req chan *http.Request
}
// Describe simply sends the two Descs in the struct to the channel.
func (c *ClusterManager) Describe(ch chan<- *prometheus.Desc) {
log.Println("describe")
ch <- c.OOMCountDesc
ch <- c.RAMUsageDesc
}
func (c *ClusterManager) SetExParameter(req *http.Request) {
c.req <- req
}
func (c *ClusterManager) Collect(ch chan<- prometheus.Metric) {
req := <-c.req
oomCountByHost, ramUsageByHost := c.ReallyExpensiveAssessmentOfTheSystemState()
for host, oomCount := range oomCountByHost {
ch <- prometheus.MustNewConstMetric(
c.OOMCountDesc,
prometheus.CounterValue,
float64(oomCount),
host,
)
}
for host, ramUsage := range ramUsageByHost {
ch <- prometheus.MustNewConstMetric(
c.RAMUsageDesc,
prometheus.GaugeValue,
ramUsage,
host,
)
}
}
func NewClusterManager(zone string) *ClusterManager {
return &ClusterManager{
Zone: zone,
OOMCountDesc: prometheus.NewDesc(
"clustermanager_oom_crashes_total",
"Number of OOM crashes.",
[]string{"host"},
prometheus.Labels{"zone": zone},
),
RAMUsageDesc: prometheus.NewDesc(
"clustermanager_ram_usage_bytes",
"RAM usage as reported to the cluster manager.",
[]string{"host"},
prometheus.Labels{"zone": zone},
),
req: make(chan int, 256),
}
}
type Registry struct {
*prometheus.Registry
collectors []ParameterSetter
}
func NewRegistry() *Registry {
r := prometheus.NewRegistry()
return &Registry{Registry: r}
}
func (r *Registry) SetExParameter(req *http.Request) {
for _, c := range r.collectors {
c.SetExParameter(req)
}
}
func (r *Registry) MustRegister(vs ...interface{}) {
for _, v := range vs {
if c, ok := v.(ParameterSetter); ok {
r.collectors = append(r.collectors , c)
}
if c, ok := v.(prometheus.Collector); ok {
r.Registry.MustRegister(c)
}
}
}
type ParameterSetter interface {
SetExParameter(req *http.Request)
}
type Gatherer interface {
prometheus.Gatherer
ParameterSetter
}
func HandlerFor(reg Gatherer, opts promhttp.HandlerOpts) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
reg.SetExParameter(req)
promhttp.HandlerFor(reg, opts).ServeHTTP(w, req)
})
}
func main() {
workerDB := NewClusterManager("db")
workerCA := NewClusterManager("ca")
// Since we are dealing with custom Collector implementations, it might
// be a good idea to try it out with a pedantic registry.
reg := NewPedanticRegistry()
reg.MustRegister(workerDB)
reg.MustRegister(workerCA)
// Expose the registered metrics via HTTP.
http.Handle("/metrics", HandlerFor(reg, promhttp.HandlerOpts{}))
http.ListenAndServe(":8080", nil)
}