Skip to content

Commit 359f856

Browse files
committed
feat(metrics): add template name as label for utask_task_state telemetry
Signed-off-by: Thomas Bétrancourt <thomas@betrancourt.net>
1 parent 12e3dcd commit 359f856

File tree

4 files changed

+101
-64
lines changed

4 files changed

+101
-64
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ BINARY = utask
22

33
MAIN_LOCATION = ./cmd
44

5-
TEST_LOCATION = ./...
5+
TEST_LOCATION ?= ./...
66
# timeout for go test is here to prevent tests running infinitely if one runResolution leads to a step that never recovers (e.g. missing push on a stepChan)
77
# 30 seconds per unit tests should be enough
88
TEST_CMD = go test -count=1 -timeout 30s -v -cover -p 1 ${TEST_LOCATION}

api/metrics.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@ import (
1717
)
1818

1919
var (
20-
metrics = promauto.NewGaugeVec(prometheus.GaugeOpts{Name: "utask_task_state"}, []string{"status", "group"})
20+
metrics = promauto.NewGaugeVec(prometheus.GaugeOpts{Name: "utask_task_state"}, []string{"status", "template", "group"})
2121
)
2222

2323
func updateMetrics(dbp zesty.DBProvider) {
24-
// utask_task_state_per_resolver_group
25-
statsResolverGroup, err := task.LoadStateCountResolverGroup(dbp)
24+
stats, err := task.LoadStateCountResolverGroup(dbp)
2625
if err != nil {
2726
logrus.Warn(err)
2827
}
29-
for group, groupStats := range statsResolverGroup {
30-
for state, count := range groupStats {
31-
metrics.WithLabelValues(state, group).Set(count)
28+
29+
for group, groupStats := range stats {
30+
for template, templateStats := range groupStats {
31+
for state, count := range templateStats {
32+
metrics.WithLabelValues(state, template, group).Set(count)
33+
}
3234
}
3335
}
3436
}

models/task/stats.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ type stateCount struct {
2727

2828
type stateCountResolverGroup struct {
2929
stateCount
30-
Group string `db:"group_name"`
30+
Template string `db:"template"`
31+
Group string `db:"group_name"`
3132
}
3233

3334
// RegisterValidationTime computes the duration between the task creation and
@@ -93,11 +94,12 @@ func LoadStateCount(dbp zesty.DBProvider, tags map[string]string) (sc map[string
9394
}
9495

9596
// LoadStateCountResolverGroup returns a map containing the count of tasks grouped by state and by resolver_group
96-
func LoadStateCountResolverGroup(dbp zesty.DBProvider) (sc map[string]map[string]float64, err error) {
97+
func LoadStateCountResolverGroup(dbp zesty.DBProvider) (sc map[string]map[string]map[string]float64, err error) {
9798
defer errors.DeferredAnnotatef(&err, "Failed to load task stats")
9899

99100
subQuery := sqlgenerator.PGsql.Select(
100101
`t."id"`,
102+
`tt."name" as "template"`,
101103
`t."state"`,
102104
`coalesce(
103105
nullif(t."resolver_groups", 'null'::jsonb),
@@ -107,11 +109,11 @@ func LoadStateCountResolverGroup(dbp zesty.DBProvider) (sc map[string]map[string
107109
From(`"task" t`).
108110
LeftJoin(`"task_template" tt ON t."id_template" = tt."id"`)
109111

110-
sel := sqlgenerator.PGsql.Select(`"group_name"`, `"state"`, `count("sq"."state") as "state_count"`).
112+
sel := sqlgenerator.PGsql.Select(`"group_name"`, `"state"`, `"sq"."template"`, `count("sq"."state") as "state_count"`).
111113
FromSelect(subQuery, "sq").
112114
Join(`jsonb_array_elements_text("sq"."groups") "group_name" ON true`).
113115
Where(`"sq"."groups" IS NOT NULL`).
114-
GroupBy(`"group_name"`, `"sq"."state"`)
116+
GroupBy(`"group_name"`, `"sq"."state"`, `"sq"."template"`)
115117

116118
query, params, err := sel.ToSql()
117119
if err != nil {
@@ -123,11 +125,15 @@ func LoadStateCountResolverGroup(dbp zesty.DBProvider) (sc map[string]map[string
123125
return nil, pgjuju.Interpret(err)
124126
}
125127

126-
sc = make(map[string]map[string]float64)
128+
sc = make(map[string]map[string]map[string]float64)
127129

128130
for _, gsc := range s {
129131
if _, exists := sc[gsc.Group]; !exists {
130-
sc[gsc.Group] = map[string]float64{
132+
sc[gsc.Group] = map[string]map[string]float64{}
133+
}
134+
135+
if _, exists := sc[gsc.Group][gsc.Template]; !exists {
136+
sc[gsc.Group][gsc.Template] = map[string]float64{
131137
StateTODO: 0,
132138
StateBlocked: 0,
133139
StateRunning: 0,
@@ -136,7 +142,8 @@ func LoadStateCountResolverGroup(dbp zesty.DBProvider) (sc map[string]map[string
136142
StateCancelled: 0,
137143
}
138144
}
139-
sc[gsc.Group][gsc.State] = gsc.Count
145+
146+
sc[gsc.Group][gsc.Template][gsc.State] = gsc.Count
140147
}
141148

142149
return sc, nil

models/task/stats_test.go

Lines changed: 78 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -116,96 +116,110 @@ func TestLoadStateCountResolverGroup(t *testing.T) {
116116
name string
117117
tasks map[string][]string
118118
templates map[string][]string
119-
wantSc map[string]map[string]float64
119+
wantSc map[string]map[string]map[string]float64
120120
}{
121121
{
122122
"no-group",
123123
map[string][]string{"task": nil},
124124
map[string][]string{"task": nil},
125-
map[string]map[string]float64{
125+
map[string]map[string]map[string]float64{
126126
"": {
127-
task.StateTODO: 1,
128-
task.StateBlocked: 0,
129-
task.StateRunning: 0,
130-
task.StateWontfix: 0,
131-
task.StateDone: 0,
132-
task.StateCancelled: 0,
127+
"task": {
128+
task.StateTODO: 1,
129+
task.StateBlocked: 0,
130+
task.StateRunning: 0,
131+
task.StateWontfix: 0,
132+
task.StateDone: 0,
133+
task.StateCancelled: 0,
134+
},
133135
},
134136
},
135137
},
136138
{
137139
"no-override",
138140
map[string][]string{"task": nil},
139141
map[string][]string{"task": {"foo"}},
140-
map[string]map[string]float64{
142+
map[string]map[string]map[string]float64{
141143
"foo": {
142-
task.StateTODO: 1,
143-
task.StateBlocked: 0,
144-
task.StateRunning: 0,
145-
task.StateWontfix: 0,
146-
task.StateDone: 0,
147-
task.StateCancelled: 0,
144+
"task": {
145+
task.StateTODO: 1,
146+
task.StateBlocked: 0,
147+
task.StateRunning: 0,
148+
task.StateWontfix: 0,
149+
task.StateDone: 0,
150+
task.StateCancelled: 0,
151+
},
148152
},
149153
},
150154
},
151155
{
152156
"with-override",
153157
map[string][]string{"task": {"bar"}},
154158
map[string][]string{"task": {"foo"}},
155-
map[string]map[string]float64{
159+
map[string]map[string]map[string]float64{
156160
"bar": {
157-
task.StateTODO: 1,
158-
task.StateBlocked: 0,
159-
task.StateRunning: 0,
160-
task.StateWontfix: 0,
161-
task.StateDone: 0,
162-
task.StateCancelled: 0,
161+
"task": {
162+
task.StateTODO: 1,
163+
task.StateBlocked: 0,
164+
task.StateRunning: 0,
165+
task.StateWontfix: 0,
166+
task.StateDone: 0,
167+
task.StateCancelled: 0,
168+
},
163169
},
164170
},
165171
},
166172
{
167173
"no-override-multiple",
168174
map[string][]string{"task": nil},
169175
map[string][]string{"task": {"foo", "bar"}},
170-
map[string]map[string]float64{
176+
map[string]map[string]map[string]float64{
171177
"foo": {
172-
task.StateTODO: 1,
173-
task.StateBlocked: 0,
174-
task.StateRunning: 0,
175-
task.StateWontfix: 0,
176-
task.StateDone: 0,
177-
task.StateCancelled: 0,
178+
"task": {
179+
task.StateTODO: 1,
180+
task.StateBlocked: 0,
181+
task.StateRunning: 0,
182+
task.StateWontfix: 0,
183+
task.StateDone: 0,
184+
task.StateCancelled: 0,
185+
},
178186
},
179187
"bar": {
180-
task.StateTODO: 1,
181-
task.StateBlocked: 0,
182-
task.StateRunning: 0,
183-
task.StateWontfix: 0,
184-
task.StateDone: 0,
185-
task.StateCancelled: 0,
188+
"task": {
189+
task.StateTODO: 1,
190+
task.StateBlocked: 0,
191+
task.StateRunning: 0,
192+
task.StateWontfix: 0,
193+
task.StateDone: 0,
194+
task.StateCancelled: 0,
195+
},
186196
},
187197
},
188198
},
189199
{
190200
"with-override-multiple",
191201
map[string][]string{"task": {"foo", "bar"}},
192202
map[string][]string{"task": {"dummy"}},
193-
map[string]map[string]float64{
203+
map[string]map[string]map[string]float64{
194204
"foo": {
195-
task.StateTODO: 1,
196-
task.StateBlocked: 0,
197-
task.StateRunning: 0,
198-
task.StateWontfix: 0,
199-
task.StateDone: 0,
200-
task.StateCancelled: 0,
205+
"task": {
206+
task.StateTODO: 1,
207+
task.StateBlocked: 0,
208+
task.StateRunning: 0,
209+
task.StateWontfix: 0,
210+
task.StateDone: 0,
211+
task.StateCancelled: 0,
212+
},
201213
},
202214
"bar": {
203-
task.StateTODO: 1,
204-
task.StateBlocked: 0,
205-
task.StateRunning: 0,
206-
task.StateWontfix: 0,
207-
task.StateDone: 0,
208-
task.StateCancelled: 0,
215+
"task": {
216+
task.StateTODO: 1,
217+
task.StateBlocked: 0,
218+
task.StateRunning: 0,
219+
task.StateWontfix: 0,
220+
task.StateDone: 0,
221+
task.StateCancelled: 0,
222+
},
209223
},
210224
},
211225
},
@@ -219,6 +233,20 @@ func TestLoadStateCountResolverGroup(t *testing.T) {
219233

220234
prefix := fmt.Sprintf("task-%d-", time.Now().UnixNano())
221235

236+
prefixedWantSc := make(map[string]map[string]map[string]float64)
237+
238+
for group, groupStats := range tt.wantSc {
239+
prefixedWantSc[group] = map[string]map[string]float64{}
240+
241+
for template, templateStats := range groupStats {
242+
prefixedWantSc[group][prefix+template] = map[string]float64{}
243+
244+
for state, count := range templateStats {
245+
prefixedWantSc[group][prefix+template][state] = count
246+
}
247+
}
248+
}
249+
222250
templates, err := createTemplates(dbp, prefix, tt.templates)
223251
if err != nil {
224252
t.Errorf("createTemplates() error = %v", err)
@@ -237,8 +265,8 @@ func TestLoadStateCountResolverGroup(t *testing.T) {
237265
return
238266
}
239267

240-
if !reflect.DeepEqual(gotSc, tt.wantSc) {
241-
t.Errorf("LoadStateCountResolverGroup() = %v, want %v", gotSc, tt.wantSc)
268+
if !reflect.DeepEqual(gotSc, prefixedWantSc) {
269+
t.Errorf("LoadStateCountResolverGroup() = %v, want %v", gotSc, prefixedWantSc)
242270
}
243271

244272
if err := dbp.Rollback(); err != nil {

0 commit comments

Comments
 (0)