Raw
  1package obs
  2
  3import (
  4	"net/http"
  5	"runtime"
  6	"strings"
  7
  8	"github.com/prometheus/client_golang/prometheus"
  9	"github.com/prometheus/client_golang/prometheus/collectors"
 10	"github.com/prometheus/client_golang/prometheus/promhttp"
 11)
 12
 13const scrapesInFlight = 2
 14
 15type Label struct {
 16	Name   string
 17	Values []string
 18}
 19
 20type Registry struct {
 21	reg  *prometheus.Registry
 22	lazy lazy
 23}
 24
 25func New() *Registry {
 26	reg := prometheus.NewRegistry()
 27	reg.MustRegister(
 28		collectors.NewGoCollector(),
 29		collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
 30		buildInfo(),
 31	)
 32	return &Registry{reg: reg}
 33}
 34
 35func buildInfo() prometheus.Collector {
 36	g := prometheus.NewGauge(prometheus.GaugeOpts{
 37		Name:        "tug_build_info",
 38		Help:        "The running tug binary: the Go version that built it.",
 39		ConstLabels: prometheus.Labels{"goversion": runtime.Version()},
 40	})
 41	g.Set(1)
 42	return g
 43}
 44
 45func (r *Registry) Handler() http.Handler {
 46	return promhttp.HandlerFor(r.reg, promhttp.HandlerOpts{MaxRequestsInFlight: scrapesInFlight})
 47}
 48
 49func (r *Registry) Prometheus() *prometheus.Registry {
 50	if r == nil {
 51		return nil
 52	}
 53	return r.reg
 54}
 55
 56type Counter struct {
 57	children map[string]prometheus.Counter
 58}
 59
 60const keySep = "\xff"
 61
 62func (r *Registry) Counter(name, help string, labels ...Label) *Counter {
 63	if r == nil {
 64		return nil
 65	}
 66	names := make([]string, len(labels))
 67	for i, l := range labels {
 68		names[i] = l.Name
 69	}
 70	vec := prometheus.NewCounterVec(prometheus.CounterOpts{Name: name, Help: help}, names)
 71	r.reg.MustRegister(vec)
 72	return children(vec, product(labels))
 73}
 74
 75func product(labels []Label) [][]string {
 76	combos := [][]string{nil}
 77	for _, l := range labels {
 78		var next [][]string
 79		for _, prefix := range combos {
 80			for _, v := range l.Values {
 81				next = append(next, append(append([]string(nil), prefix...), v))
 82			}
 83		}
 84		combos = next
 85	}
 86	return combos
 87}
 88
 89func children(vec *prometheus.CounterVec, combos [][]string) *Counter {
 90	c := &Counter{children: map[string]prometheus.Counter{}}
 91	for _, values := range combos {
 92		c.children[strings.Join(values, keySep)] = vec.WithLabelValues(values...)
 93	}
 94	return c
 95}
 96
 97func (c *Counter) Inc(values ...string) {
 98	if c == nil {
 99		return
100	}
101	if child, ok := c.children[strings.Join(values, keySep)]; ok {
102		child.Inc()
103	}
104}