Skip to content

Commit ebc4b67

Browse files
authored
[Feature] Global Metrics (#1668)
1 parent a571a19 commit ebc4b67

File tree

77 files changed

+1761
-66
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1761
-66
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
- (Feature) (Analytics) Metadata
1919
- (Feature) (Analytics) StatefulSet
2020
- (Feature) Imported ArangoBackup Cleanup
21+
- (Feature) Global Metrics
2122

2223
## [1.2.40](https://github.com/arangodb/kube-arangodb/tree/1.2.40) (2024-04-10)
2324
- (Feature) Add Core fields to the Scheduler Container Spec

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ run-unit-tests: $(SOURCES)
703703
$(REPOPATH)/pkg/storage/... \
704704
$(REPOPATH)/pkg/crd/... \
705705
$(REPOPATH)/pkg/util/... \
706+
$(REPOPATH)/pkg/generated/metric_descriptions/... \
706707
$(REPOPATH)/cmd/... \
707708
$(REPOPATH)/pkg/handlers/...
708709

docs/generated/metrics/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ has_toc: false
1414

1515
| Name | Namespace | Group | Type | Description |
1616
|:-------------------------------------------------------------------------------------------------------------------------------------:|:-----------------:|:-----------------:|:-------:|:--------------------------------------------------------------------------------------|
17+
| [arango_operator_objects_processed](./arango_operator_objects_processed.md) | arango_operator | objects | Counter | Number of the processed objects |
1718
| [arangodb_operator_agency_errors](./arangodb_operator_agency_errors.md) | arangodb_operator | agency | Counter | Current count of agency cache fetch errors |
1819
| [arangodb_operator_agency_fetches](./arangodb_operator_agency_fetches.md) | arangodb_operator | agency | Counter | Current count of agency cache fetches |
1920
| [arangodb_operator_agency_index](./arangodb_operator_agency_index.md) | arangodb_operator | agency | Gauge | Current index of the agency cache |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
layout: page
3+
title: arango_operator_objects_processed
4+
parent: List of available metrics
5+
---
6+
7+
# arango_operator_objects_processed (Counter)
8+
9+
## Description
10+
11+
Number of the processed objects
12+
13+
## Labels
14+
15+
| Label | Description |
16+
|:-------------:|:--------------|
17+
| operator_name | Operator Name |

internal/metrics.go

+57-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -38,6 +38,9 @@ var metricsGoTemplate []byte
3838
//go:embed metrics.item.go.tmpl
3939
var metricsItemGoTemplate []byte
4040

41+
//go:embed metrics.item.go_test.tmpl
42+
var metricsItemGoTestTemplate []byte
43+
4144
//go:embed metrics.item.tmpl
4245
var metricItemTemplate []byte
4346

@@ -98,6 +101,8 @@ type Metric struct {
98101
Type string `json:"type" yaml:"type"`
99102
ShortDescription string `json:"shortDescription" yaml:"shortDescription"`
100103

104+
Global bool `json:"global" yaml:"global"`
105+
101106
Labels []Label `json:"labels" yaml:"labels"`
102107
AlertingRules []Alerting `json:"alertingRules" yaml:"alertingRules"`
103108
}
@@ -277,22 +282,22 @@ func generateLabels(labels []Label) string {
277282

278283
func generateMetricsGO(root string, in MetricsDoc) error {
279284
i, err := template.New("metrics").Parse(string(metricsItemGoTemplate))
285+
if err != nil {
286+
return err
287+
}
280288

289+
t, err := template.New("metrics").Parse(string(metricsItemGoTestTemplate))
281290
if err != nil {
282291
return err
283292
}
293+
284294
for _, namespace := range in.Namespaces.Keys() {
285295
for _, g := range in.Namespaces[namespace].Keys() {
286296
for _, metric := range in.Namespaces[namespace][g].Keys() {
287297
details := in.Namespaces[namespace][g][metric]
288298

289299
mname := fmt.Sprintf("%s_%s_%s", namespace, g, metric)
290300

291-
out, err := os.OpenFile(path.Join(root, fmt.Sprintf("%s.go", mname)), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
292-
if err != nil {
293-
return err
294-
}
295-
296301
parts := strings.Split(mname, "_")
297302
tparts := strings.Split(strings.Title(strings.Join(parts, " ")), " ")
298303

@@ -311,6 +316,10 @@ func generateMetricsGO(root string, in MetricsDoc) error {
311316
params = append(params, "value float64")
312317
keys = append(keys, "value")
313318

319+
var mapTypes = map[string]string{}
320+
var mapKeys []string
321+
var mapIKeys = map[string]string{}
322+
314323
for _, label := range details.Labels {
315324
v := strings.Split(strings.ToLower(label.Key), "_")
316325
for id := range v {
@@ -323,29 +332,60 @@ func generateMetricsGO(root string, in MetricsDoc) error {
323332

324333
k := strings.Join(v, "")
325334

335+
v[0] = strings.Title(v[0])
336+
337+
kPublic := strings.Join(v, "")
338+
326339
keys = append(keys, k)
340+
mapKeys = append(mapKeys, kPublic)
341+
342+
mapIKeys[kPublic] = k
327343

328344
if t := label.Type; t != nil {
329345
params = append(params, fmt.Sprintf("%s %s", k, *t))
346+
mapTypes[kPublic] = *t
330347
} else {
331348
params = append(params, fmt.Sprintf("%s string", k))
349+
mapTypes[kPublic] = "string"
332350
}
333351
}
334352

335-
if err := i.Execute(out, map[string]interface{}{
336-
"name": mname,
337-
"fname": strings.Join(fnameParts, ""),
338-
"ename": strings.Join(tparts, ""),
339-
"shortDescription": details.ShortDescription,
340-
"labels": generateLabels(details.Labels),
341-
"type": details.Type,
342-
"fparams": strings.Join(params, ", "),
343-
"fkeys": strings.Join(keys, ", "),
344-
}); err != nil {
353+
save := func(template *template.Template, path string) error {
354+
out, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
355+
if err != nil {
356+
return err
357+
}
358+
359+
if err := template.Execute(out, map[string]interface{}{
360+
"name": mname,
361+
"fname": strings.Join(fnameParts, ""),
362+
"ename": strings.Join(tparts, ""),
363+
"shortDescription": details.ShortDescription,
364+
"global": details.Global,
365+
"labels": generateLabels(details.Labels),
366+
"type": details.Type,
367+
"mapTypes": mapTypes,
368+
"mapKeys": mapKeys,
369+
"mapIKeys": mapIKeys,
370+
"args": strings.Join(params[1:], ", "),
371+
"fparams": strings.Join(params, ", "),
372+
"fkeys": strings.Join(keys, ", "),
373+
}); err != nil {
374+
return err
375+
}
376+
377+
if err := out.Close(); err != nil {
378+
return err
379+
}
380+
381+
return nil
382+
}
383+
384+
if err := save(i, path.Join(root, fmt.Sprintf("%s.go", mname))); err != nil {
345385
return err
346386
}
347387

348-
if err := out.Close(); err != nil {
388+
if err := save(t, path.Join(root, fmt.Sprintf("%s_test.go", mname))); err != nil {
349389
return err
350390
}
351391
}

internal/metrics.go.tmpl

+23
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ import (
2828
var (
2929
descriptions []metrics.Description
3030
descriptionsLock sync.Mutex
31+
32+
collectors []metrics.Collector
33+
collectorsLock sync.Mutex
3134
)
3235

3336
func registerDescription( d ... metrics.Description) {
@@ -41,9 +44,29 @@ func registerDescription( d ... metrics.Description) {
4144
descriptions = append(descriptions, d...)
4245
}
4346

47+
func registerCollector( d ... metrics.Collector) {
48+
if len(d) == 0 {
49+
return
50+
}
51+
52+
collectorsLock.Lock()
53+
defer collectorsLock.Unlock()
54+
55+
collectors = append(collectors, d...)
56+
}
57+
4458
func Descriptions (c metrics.PushDescription) {
4559
descriptionsLock.Lock()
4660
defer descriptionsLock.Unlock()
4761

4862
c.Push(descriptions...)
63+
}
64+
65+
func Collectors (c metrics.PushMetric) {
66+
collectorsLock.Lock()
67+
defer collectorsLock.Unlock()
68+
69+
for _, collector := range collectors {
70+
collector.CollectMetrics(c)
71+
}
4972
}

internal/metrics.item.go.tmpl

+139-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{{- $root := . -}}
12
//
23
// DISCLAIMER
34
//
@@ -20,20 +21,156 @@
2021

2122
package metric_descriptions
2223

23-
import "github.com/arangodb/kube-arangodb/pkg/util/metrics"
24+
import (
25+
"github.com/arangodb/kube-arangodb/pkg/util/metrics"
26+
{{- if .global }}
27+
28+
"sync"
29+
{{- end }}
30+
)
2431

2532
var (
2633
{{ .fname }} = metrics.NewDescription("{{ .name }}", "{{ .shortDescription }}", {{ .labels }}, nil)
2734
)
2835

2936
func init() {
3037
registerDescription({{ .fname }})
38+
{{- if .global }}
39+
registerCollector({{ .fname }}Global)
40+
{{- end }}
3141
}
3242

3343
func {{ .ename }}() metrics.Description {
3444
return {{ .fname }}
3545
}
3646

47+
{{- if .global }}
48+
49+
func {{ .ename }}Get({{ .args }}) float64 {
50+
return {{ .fname }}Global.Get({{ .ename }}Item{
51+
{{- range $i, $field := .mapKeys }}
52+
{{ $field }}: {{ index $root.mapIKeys $field }},
53+
{{- end }}
54+
})
55+
}
56+
57+
func {{ .ename }}Add({{ .fparams }}) {
58+
{{ .fname }}Global.Add(value, {{ .ename }}Item{
59+
{{- range $i, $field := .mapKeys }}
60+
{{ $field }}: {{ index $root.mapIKeys $field }},
61+
{{- end }}
62+
})
63+
}
64+
{{- if eq .type "Counter" }}
65+
66+
func {{ .ename }}Inc({{ .args }}) {
67+
{{ .fname }}Global.Inc({{ .ename }}Item{
68+
{{- range $i, $field := .mapKeys }}
69+
{{ $field }}: {{ index $root.mapIKeys $field }},
70+
{{- end }}
71+
})
72+
}
73+
{{- end }}
74+
75+
func Get{{ .ename }}Factory() {{ .ename }}Factory {
76+
return {{ .fname }}Global
77+
}
78+
79+
var {{ .fname }}Global = &{{ .fname }}Factory{
80+
items: {{ .fname }}Items{},
81+
}
82+
83+
type {{ .ename }}Factory interface {
84+
Get(object {{ .ename }}Item) float64
85+
Add(value float64, object {{ .ename }}Item)
86+
Remove(object {{ .ename }}Item)
87+
Items() []{{ .ename }}Item
88+
{{- if eq .type "Counter" }}
89+
90+
Inc(object {{ .ename }}Item)
91+
{{- end }}
92+
}
93+
94+
type {{ .fname }}Factory struct {
95+
lock sync.RWMutex
96+
97+
items {{ .fname }}Items
98+
}
99+
100+
func (a *{{ .fname }}Factory) Get(object {{ .ename }}Item) float64 {
101+
a.lock.Lock()
102+
defer a.lock.Unlock()
103+
104+
v, ok := a.items[object]
105+
if !ok {
106+
return 0
107+
}
108+
109+
return v
110+
}
111+
112+
func (a *{{ .fname }}Factory) Add(value float64, object {{ .ename }}Item) {
113+
a.lock.Lock()
114+
defer a.lock.Unlock()
115+
116+
v, ok := a.items[object]
117+
if !ok {
118+
a.items[object] = value
119+
return
120+
}
121+
122+
a.items[object] = value + v
123+
}
124+
125+
func (a *{{ .fname }}Factory) Remove(obj {{ .ename }}Item) {
126+
a.lock.Lock()
127+
defer a.lock.Unlock()
128+
129+
delete(a.items, obj)
130+
}
131+
132+
func (a *{{ .fname }}Factory) Items() []{{ .ename }}Item {
133+
a.lock.Lock()
134+
defer a.lock.Unlock()
135+
136+
var r = make([]{{ .ename }}Item, 0, len(a.items))
137+
138+
for k := range a.items {
139+
r = append(r, k)
140+
}
141+
142+
return r
143+
}
144+
{{- if eq .type "Counter" }}
145+
146+
func (a *{{ .fname }}Factory) Inc(object {{ .ename }}Item) {
147+
a.Add(1, object)
148+
}
149+
{{- end }}
150+
151+
func (a *{{ .fname }}Factory) CollectMetrics(in metrics.PushMetric) {
152+
a.lock.RLock()
153+
defer a.lock.RUnlock()
154+
155+
for k, v := range a.items {
156+
in.Push({{ .fname }}.{{ .type }}(v{{- range .mapKeys }}, k.{{ . }}{{- end }}))
157+
}
158+
}
159+
160+
func (a *{{ .fname }}Factory) CollectDescriptions(in metrics.PushDescription) {
161+
in.Push({{ .fname }})
162+
}
163+
164+
type {{ .fname }}Items map[{{ .ename }}Item]float64
165+
166+
type {{ .ename }}Item struct {
167+
{{- range .mapKeys }}
168+
{{ . }} {{ index $root.mapTypes . }}
169+
{{- end }}
170+
}
171+
{{- else }}
172+
37173
func {{ .ename }}{{ .type }}({{ .fparams }}) metrics.Metric {
38174
return {{ .ename }}().{{ .type }}({{ .fkeys }})
39-
}
175+
}
176+
{{- end }}

0 commit comments

Comments
 (0)