Skip to content

Commit 0c116b5

Browse files
committed
fix: map traversing is unstable in go which leaded to a mix of labels and values with the current implementation
1 parent c0020a5 commit 0c116b5

File tree

2 files changed

+44
-29
lines changed

2 files changed

+44
-29
lines changed

internal/metrics/metrics.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package metrics
22

33
import (
44
"errors"
5+
"sort"
56
"sync"
67

78
"github.com/prometheus/client_golang/prometheus"
@@ -38,22 +39,22 @@ func buildMetrics(staticMetrics map[string]string) *Metrics {
3839
percentileObjectives := map[float64]float64{
3940
0.5: 0.05, 0.75: 0.05, 0.9: 0.01, 0.95: 0.001, 0.99: 0.001, 0.9999: 0.00001, 1.0: 0.00001,
4041
}
41-
42+
labelKeys := getStaticMetricLabelKeys(staticMetrics)
4243
return &Metrics{
4344
Setup: prometheus.NewSummaryVec(prometheus.SummaryOpts{
4445
Namespace: metricNamespace,
4546
Subsystem: metricSubsystem,
4647
Name: "setup",
4748
Help: "Duration of setup functions.",
4849
Objectives: percentileObjectives,
49-
}, append([]string{TestNameLabel, ResultLabel}, getStaticMetricLabelKeys(staticMetrics)...)),
50+
}, append([]string{TestNameLabel, ResultLabel}, labelKeys...)),
5051
Iteration: prometheus.NewSummaryVec(prometheus.SummaryOpts{
5152
Namespace: metricNamespace,
5253
Subsystem: metricSubsystem,
5354
Name: "iteration",
5455
Help: "Duration of iteration functions.",
5556
Objectives: percentileObjectives,
56-
}, append([]string{TestNameLabel, StageLabel, ResultLabel}, getStaticMetricLabelKeys(staticMetrics)...)),
57+
}, append([]string{TestNameLabel, StageLabel, ResultLabel}, labelKeys...)),
5758
}
5859
}
5960

@@ -118,17 +119,22 @@ func (metrics *Metrics) RecordIterationStage(name string, stage string, result R
118119
}
119120

120121
func getStaticMetricLabelKeys(staticMetrics map[string]string) []string {
121-
data := make([]string, 0, len(staticMetrics))
122-
for k := range staticMetrics {
123-
data = append(data, k)
124-
}
125-
return data
122+
return sortedKeys(staticMetrics)
126123
}
127124

128125
func getStaticMetricLabelValues(staticMetrics map[string]string) []string {
129126
data := make([]string, 0, len(staticMetrics))
130-
for _, v := range staticMetrics {
131-
data = append(data, v)
127+
for _, v := range sortedKeys(staticMetrics) {
128+
data = append(data, staticMetrics[v])
132129
}
133130
return data
134131
}
132+
133+
func sortedKeys(staticMetrics map[string]string) []string {
134+
keys := make([]string, 0, len(staticMetrics))
135+
for k := range staticMetrics {
136+
keys = append(keys, k)
137+
}
138+
sort.Strings(keys)
139+
return keys
140+
}

internal/metrics/metrics_test.go

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package metrics_test
22

33
import (
4+
"bytes"
5+
"fmt"
46
"testing"
57

6-
"github.com/prometheus/client_golang/prometheus"
78
"github.com/prometheus/client_golang/prometheus/testutil"
89
"github.com/stretchr/testify/assert"
910
"github.com/stretchr/testify/require"
@@ -13,29 +14,37 @@ import (
1314

1415
func TestMetrics_Init_IsSafe(t *testing.T) {
1516
t.Parallel()
16-
metrics.InitWithStaticMetrics(true, map[string]string{
17-
"product": "fps",
18-
"f1_id": "myid",
19-
}) // race detector assertion
17+
labels := map[string]string{
18+
"product": "fps",
19+
"customer": "fake-customer",
20+
"f1_id": "myid",
21+
"labelx": "vx",
22+
}
23+
metrics.InitWithStaticMetrics(true, labels) // race detector assertion
2024
for range 10 {
2125
go func() {
22-
metrics.InitWithStaticMetrics(true, map[string]string{
23-
"product": "fps",
24-
"f1_id": "myid",
25-
})
26+
metrics.InitWithStaticMetrics(true, labels)
2627
}()
2728
}
2829
assert.True(t, metrics.Instance().IterationMetricsEnabled)
2930
metrics.Instance().RecordIterationResult("test1", metrics.SuccessResult, 1)
3031
assert.Equal(t, 1, testutil.CollectAndCount(metrics.Instance().Iteration, "form3_loadtest_iteration"))
31-
o, err := metrics.Instance().Iteration.MetricVec.GetMetricWith(prometheus.Labels{
32-
metrics.TestNameLabel: "test1",
33-
metrics.StageLabel: metrics.IterationStage,
34-
metrics.ResultLabel: metrics.SuccessResult.String(),
35-
"product": "fps",
36-
"f1_id": "myid",
37-
})
38-
require.NoError(t, err)
39-
assert.Contains(t, o.Desc().String(), "product")
40-
assert.Contains(t, o.Desc().String(), "f1_id")
32+
33+
expected := `
34+
# HELP form3_loadtest_iteration Duration of iteration functions.
35+
# TYPE form3_loadtest_iteration summary
36+
`
37+
quantileFormat := `
38+
form3_loadtest_iteration{customer="fake-customer",f1_id="myid",labelx="vx",product="fps",result="success",stage="iteration",test="test1",quantile="%s"} 1
39+
`
40+
for _, quantile := range []string{"0.5", "0.75", "0.9", "0.95", "0.99", "0.9999", "1.0"} {
41+
expected += fmt.Sprintf(quantileFormat, quantile)
42+
}
43+
44+
expected += `
45+
form3_loadtest_iteration_sum{customer="fake-customer",f1_id="myid",labelx="vx",product="fps",result="success",stage="iteration",test="test1"} 1
46+
form3_loadtest_iteration_count{customer="fake-customer",f1_id="myid",labelx="vx",product="fps",result="success",stage="iteration",test="test1"} 1
47+
`
48+
r := bytes.NewReader([]byte(expected))
49+
require.NoError(t, testutil.CollectAndCompare(metrics.Instance().Iteration, r))
4150
}

0 commit comments

Comments
 (0)