package obs import ( "net/http" "runtime" "strings" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" ) const scrapesInFlight = 2 type Label struct { Name string Values []string } type Registry struct { reg *prometheus.Registry lazy lazy } func New() *Registry { reg := prometheus.NewRegistry() reg.MustRegister( collectors.NewGoCollector(), collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), buildInfo(), ) return &Registry{reg: reg} } func buildInfo() prometheus.Collector { g := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "tug_build_info", Help: "The running tug binary: the Go version that built it.", ConstLabels: prometheus.Labels{"goversion": runtime.Version()}, }) g.Set(1) return g } func (r *Registry) Handler() http.Handler { return promhttp.HandlerFor(r.reg, promhttp.HandlerOpts{MaxRequestsInFlight: scrapesInFlight}) } func (r *Registry) Prometheus() *prometheus.Registry { if r == nil { return nil } return r.reg } type Counter struct { children map[string]prometheus.Counter } const keySep = "\xff" func (r *Registry) Counter(name, help string, labels ...Label) *Counter { if r == nil { return nil } names := make([]string, len(labels)) for i, l := range labels { names[i] = l.Name } vec := prometheus.NewCounterVec(prometheus.CounterOpts{Name: name, Help: help}, names) r.reg.MustRegister(vec) return children(vec, product(labels)) } func product(labels []Label) [][]string { combos := [][]string{nil} for _, l := range labels { var next [][]string for _, prefix := range combos { for _, v := range l.Values { next = append(next, append(append([]string(nil), prefix...), v)) } } combos = next } return combos } func children(vec *prometheus.CounterVec, combos [][]string) *Counter { c := &Counter{children: map[string]prometheus.Counter{}} for _, values := range combos { c.children[strings.Join(values, keySep)] = vec.WithLabelValues(values...) } return c } func (c *Counter) Inc(values ...string) { if c == nil { return } if child, ok := c.children[strings.Join(values, keySep)]; ok { child.Inc() } }