Skip to content

Commit eeb6fde

Browse files
authored
Merge pull request #8 from simonpasquier/allow-custom-registry
Allow to use custom registerer for metrics
2 parents 04d4d0e + 97b2c61 commit eeb6fde

File tree

3 files changed

+172
-37
lines changed

3 files changed

+172
-37
lines changed

metrics/metric_observer.go

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,15 @@ import (
66

77
"github.com/openshift-online/async-routine"
88
"github.com/prometheus/client_golang/prometheus"
9+
"github.com/prometheus/client_golang/prometheus/promauto"
910
)
1011

1112
var _ async.RoutinesObserver = (*metricObserver)(nil)
1213

13-
type metricObserver struct{}
14-
15-
var (
16-
runningRoutines = prometheus.NewGauge(
17-
prometheus.GaugeOpts{
18-
Name: "async_routine_manager_routines",
19-
Help: "Number of running routines.",
20-
},
21-
)
22-
23-
runningRoutinesByName = prometheus.NewGaugeVec(
24-
prometheus.GaugeOpts{
25-
Name: "async_routine_manager_routine_instances",
26-
Help: "Number of running instances of a given routine.",
27-
},
28-
[]string{"routine_name", "data"},
29-
)
30-
)
31-
32-
func init() {
33-
prometheus.MustRegister(runningRoutines)
34-
prometheus.MustRegister(runningRoutinesByName)
14+
type metricObserver struct {
15+
registerer prometheus.Registerer
16+
runningRoutines prometheus.Gauge
17+
runningRoutinesByName *prometheus.GaugeVec
3518
}
3619

3720
func mapToString(m map[string]string) string {
@@ -55,13 +38,13 @@ func mapToString(m map[string]string) string {
5538
}
5639

5740
func (m *metricObserver) RoutineStarted(routine async.AsyncRoutine) {
58-
runningRoutinesByName.
41+
m.runningRoutinesByName.
5942
With(prometheus.Labels{"routine_name": routine.Name(), "data": mapToString(routine.GetData())}).
6043
Inc()
6144
}
6245

6346
func (m *metricObserver) RoutineFinished(routine async.AsyncRoutine) {
64-
runningRoutinesByName.
47+
m.runningRoutinesByName.
6548
With(prometheus.Labels{"routine_name": routine.Name(), "data": mapToString(routine.GetData())}).
6649
Dec()
6750
}
@@ -70,12 +53,46 @@ func (m *metricObserver) RoutineExceededTimebox(routine async.AsyncRoutine) {
7053
}
7154

7255
func (m *metricObserver) RunningRoutineCount(count int) {
73-
runningRoutines.Set(float64(count))
56+
m.runningRoutines.Set(float64(count))
7457
}
7558

7659
func (m *metricObserver) RunningRoutineByNameCount(name string, count int) {
7760
}
7861

79-
func NewMetricObserver() async.RoutinesObserver {
80-
return &metricObserver{}
62+
// MetricOption defines options for the metrics observer.
63+
type MetricOption func(*metricObserver)
64+
65+
// WithRegisterer configures the Prometheus registry where to register metrics.
66+
func WithRegisterer(r prometheus.Registerer) MetricOption {
67+
return func(observer *metricObserver) {
68+
observer.registerer = r
69+
}
70+
}
71+
72+
// NewMetricObserver returns an observer which tracks metrics for the async
73+
// routines.
74+
func NewMetricObserver(opts ...MetricOption) async.RoutinesObserver {
75+
observer := &metricObserver{
76+
registerer: prometheus.DefaultRegisterer,
77+
}
78+
79+
for _, opt := range opts {
80+
opt(observer)
81+
}
82+
83+
observer.runningRoutines = promauto.With(observer.registerer).NewGauge(
84+
prometheus.GaugeOpts{
85+
Name: "async_routine_manager_routines",
86+
Help: "Number of running routines.",
87+
},
88+
)
89+
observer.runningRoutinesByName = promauto.With(observer.registerer).NewGaugeVec(
90+
prometheus.GaugeOpts{
91+
Name: "async_routine_manager_routine_instances",
92+
Help: "Number of running instances of a given routine.",
93+
},
94+
[]string{"routine_name", "data"},
95+
)
96+
97+
return observer
8198
}

metrics/metric_observer_suite_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package metrics
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestMetricsObserver(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Metrics Suite")
13+
}

metrics/metric_observer_test.go

Lines changed: 115 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,124 @@
11
package metrics
22

33
import (
4-
"testing"
4+
"bytes"
55

6+
. "github.com/onsi/ginkgo/v2/dsl/core"
7+
. "github.com/onsi/ginkgo/v2/dsl/table"
8+
. "github.com/onsi/gomega"
9+
"github.com/openshift-online/async-routine"
610
"github.com/prometheus/client_golang/prometheus"
711
"github.com/prometheus/client_golang/prometheus/testutil"
12+
"go.uber.org/mock/gomock"
813
)
914

10-
func TestPrometheusMetrics(t *testing.T) {
11-
problems, err := testutil.GatherAndLint(prometheus.DefaultGatherer)
12-
if err != nil {
13-
t.Fatal(err)
14-
}
15+
var _ = Describe("Metrics Observer", func() {
16+
DescribeTable("Updates metrics",
17+
func(updateFn func(async.RoutinesObserver), expected string) {
18+
registry := prometheus.NewPedanticRegistry()
19+
observer := NewMetricObserver(WithRegisterer(registry))
1520

16-
for _, p := range problems {
17-
t.Errorf("found linting issue: %s: %s", p.Metric, p.Text)
18-
}
19-
}
21+
updateFn(observer)
22+
23+
err := testutil.GatherAndCompare(registry, bytes.NewBufferString(expected))
24+
Expect(err).NotTo(HaveOccurred())
25+
26+
problems, err := testutil.GatherAndLint(registry)
27+
Expect(err).NotTo(HaveOccurred())
28+
Expect(problems).To(BeEmpty())
29+
},
30+
Entry("from initial state",
31+
func(async.RoutinesObserver) {},
32+
`# HELP async_routine_manager_routines Number of running routines.
33+
# TYPE async_routine_manager_routines gauge
34+
async_routine_manager_routines 0
35+
`,
36+
),
37+
Entry("when 1 routine is started",
38+
func(observer async.RoutinesObserver) {
39+
ctrl := gomock.NewController(GinkgoT())
40+
41+
routine := async.NewMockAsyncRoutine(ctrl)
42+
routine.EXPECT().
43+
Name().
44+
Return("test").
45+
Times(1)
46+
routine.EXPECT().
47+
GetData().
48+
Return(nil).
49+
Times(1)
50+
51+
observer.RoutineStarted(routine)
52+
observer.RunningRoutineCount(1)
53+
},
54+
`# HELP async_routine_manager_routine_instances Number of running instances of a given routine.
55+
# TYPE async_routine_manager_routine_instances gauge
56+
async_routine_manager_routine_instances{data="",routine_name="test"} 1
57+
# HELP async_routine_manager_routines Number of running routines.
58+
# TYPE async_routine_manager_routines gauge
59+
async_routine_manager_routines 1
60+
`),
61+
Entry("when 2 routines (1 with data) are started",
62+
func(observer async.RoutinesObserver) {
63+
ctrl := gomock.NewController(GinkgoT())
64+
65+
routine := async.NewMockAsyncRoutine(ctrl)
66+
routine.EXPECT().
67+
Name().
68+
Return("test").
69+
Times(1)
70+
routine.EXPECT().
71+
GetData().
72+
Return(nil).
73+
Times(1)
74+
observer.RoutineStarted(routine)
75+
76+
routine2 := async.NewMockAsyncRoutine(ctrl)
77+
routine2.EXPECT().
78+
Name().
79+
Return("test2")
80+
routine2.EXPECT().
81+
GetData().
82+
Return(map[string]string{"foo": "bar"}).
83+
Times(1)
84+
85+
observer.RoutineStarted(routine2)
86+
observer.RunningRoutineCount(2)
87+
},
88+
`# HELP async_routine_manager_routine_instances Number of running instances of a given routine.
89+
# TYPE async_routine_manager_routine_instances gauge
90+
async_routine_manager_routine_instances{data="",routine_name="test"} 1
91+
async_routine_manager_routine_instances{data="foo=bar",routine_name="test2"} 1
92+
# HELP async_routine_manager_routines Number of running routines.
93+
# TYPE async_routine_manager_routines gauge
94+
async_routine_manager_routines 2
95+
`,
96+
),
97+
Entry("when 1 routine is started then stopped",
98+
func(observer async.RoutinesObserver) {
99+
ctrl := gomock.NewController(GinkgoT())
100+
101+
routine := async.NewMockAsyncRoutine(ctrl)
102+
routine.EXPECT().
103+
Name().
104+
Return("test").
105+
Times(2)
106+
routine.EXPECT().
107+
GetData().
108+
Return(nil).
109+
Times(2)
110+
111+
observer.RoutineStarted(routine)
112+
observer.RoutineFinished(routine)
113+
observer.RunningRoutineCount(0)
114+
},
115+
`# HELP async_routine_manager_routine_instances Number of running instances of a given routine.
116+
# TYPE async_routine_manager_routine_instances gauge
117+
async_routine_manager_routine_instances{data="",routine_name="test"} 0
118+
# HELP async_routine_manager_routines Number of running routines.
119+
# TYPE async_routine_manager_routines gauge
120+
async_routine_manager_routines 0
121+
`,
122+
),
123+
)
124+
})

0 commit comments

Comments
 (0)