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}