diff --git a/modules/generator/registry/gauge.go b/modules/generator/registry/gauge.go index e0ca82c882a..8cfa90702fc 100644 --- a/modules/generator/registry/gauge.go +++ b/modules/generator/registry/gauge.go @@ -24,6 +24,8 @@ type gauge struct { onAddSeries func(count uint32) bool onRemoveSeries func(count uint32) + + externalLabels map[string]string } type gaugeSeries struct { @@ -31,6 +33,8 @@ type gaugeSeries struct { labels LabelPair value *atomic.Float64 lastUpdated *atomic.Int64 + lb *labels.Builder + baseLabels labels.Labels } var ( @@ -43,7 +47,7 @@ const ( set = "set" ) -func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32)) *gauge { +func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(count uint32), externalLabels map[string]string) *gauge { if onAddSeries == nil { onAddSeries = func(uint32) bool { return true @@ -58,6 +62,7 @@ func newGauge(name string, onAddSeries func(uint32) bool, onRemoveSeries func(co series: make(map[uint64]*gaugeSeries), onAddSeries: onAddSeries, onRemoveSeries: onRemoveSeries, + externalLabels: externalLabels, } } @@ -107,10 +112,23 @@ func (g *gauge) updateSeries(labelValueCombo *LabelValueCombo, value float64, op } func (g *gauge) newSeries(labelValueCombo *LabelValueCombo, value float64) *gaugeSeries { + // base labels + baseLabels := make(labels.Labels, 1+len(g.externalLabels)) + + // add metric name + baseLabels = append(baseLabels, labels.Label{Name: labels.MetricName, Value: g.metricName}) + + // add external labels + for name, value := range g.externalLabels { + baseLabels = append(baseLabels, labels.Label{Name: name, Value: value}) + } + return &gaugeSeries{ labels: labelValueCombo.getLabelPair(), value: atomic.NewFloat64(value), lastUpdated: atomic.NewInt64(time.Now().UnixMilli()), + lb: labels.NewBuilder(baseLabels), + baseLabels: baseLabels, } } @@ -127,43 +145,24 @@ func (g *gauge) name() string { return g.metricName } -func (g *gauge) collectMetrics(appender storage.Appender, timeMs int64, externalLabels map[string]string) (activeSeries int, err error) { +func (g *gauge) collectMetrics(appender storage.Appender, timeMs int64, _ map[string]string) (activeSeries int, err error) { g.seriesMtx.RLock() defer g.seriesMtx.RUnlock() activeSeries = len(g.series) - labelsCount := 0 - if activeSeries > 0 && g.series[0] != nil { - labelsCount = len(g.series[0].labels.names) - } - - // base labels - baseLabels := make(labels.Labels, 1+len(externalLabels)+labelsCount) - - // add metric name - baseLabels = append(baseLabels, labels.Label{Name: labels.MetricName, Value: g.metricName}) - - // add external labels - for name, value := range externalLabels { - baseLabels = append(baseLabels, labels.Label{Name: name, Value: value}) - } - - // TODO: avoid allocation on each collection - lb := labels.NewBuilder(baseLabels) - for _, s := range g.series { t := time.UnixMilli(timeMs) // reset labels for every series - lb.Reset(baseLabels) + s.lb.Reset(s.baseLabels) // set series-specific labels for i, name := range s.labels.names { - lb.Set(name, s.labels.values[i]) + s.lb.Set(name, s.labels.values[i]) } - _, err = appender.Append(0, lb.Labels(), t.UnixMilli(), s.value.Load()) + _, err = appender.Append(0, s.lb.Labels(), t.UnixMilli(), s.value.Load()) if err != nil { return } diff --git a/modules/generator/registry/gauge_test.go b/modules/generator/registry/gauge_test.go index f5124f91564..4723a76ee6e 100644 --- a/modules/generator/registry/gauge_test.go +++ b/modules/generator/registry/gauge_test.go @@ -17,7 +17,7 @@ func Test_gaugeInc(t *testing.T) { return true } - c := newGauge("my_gauge", onAdd, nil) + c := newGauge("my_gauge", onAdd, nil, nil) c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0) c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0) @@ -52,7 +52,7 @@ func TestGaugeDifferentLabels(t *testing.T) { return true } - c := newGauge("my_gauge", onAdd, nil) + c := newGauge("my_gauge", onAdd, nil, nil) c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0) c.Inc(newLabelValueCombo([]string{"another_label"}, []string{"another_value"}), 2.0) @@ -74,7 +74,7 @@ func Test_gaugeSet(t *testing.T) { return true } - c := newGauge("my_gauge", onAdd, nil) + c := newGauge("my_gauge", onAdd, nil, nil) c.Set(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0) c.Set(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0) @@ -109,7 +109,7 @@ func Test_gauge_cantAdd(t *testing.T) { return canAdd } - c := newGauge("my_gauge", onAdd, nil) + c := newGauge("my_gauge", onAdd, nil, nil) // allow adding new series canAdd = true @@ -145,7 +145,7 @@ func Test_gauge_removeStaleSeries(t *testing.T) { removedSeries++ } - c := newGauge("my_gauge", nil, onRemove) + c := newGauge("my_gauge", nil, onRemove, nil) timeMs := time.Now().UnixMilli() c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0) @@ -180,7 +180,7 @@ func Test_gauge_removeStaleSeries(t *testing.T) { } func Test_gauge_externalLabels(t *testing.T) { - c := newGauge("my_gauge", nil, nil) + c := newGauge("my_gauge", nil, nil, map[string]string{"external_label": "external_value"}) c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-1"}), 1.0) c.Inc(newLabelValueCombo([]string{"label"}, []string{"value-2"}), 2.0) @@ -190,11 +190,11 @@ func Test_gauge_externalLabels(t *testing.T) { newSample(map[string]string{"__name__": "my_gauge", "label": "value-1", "external_label": "external_value"}, collectionTimeMs, 1), newSample(map[string]string{"__name__": "my_gauge", "label": "value-2", "external_label": "external_value"}, collectionTimeMs, 2), } - collectMetricAndAssert(t, c, collectionTimeMs, map[string]string{"external_label": "external_value"}, 2, expectedSamples, nil) + collectMetricAndAssert(t, c, collectionTimeMs, nil, 2, expectedSamples, nil) } func Test_gauge_concurrencyDataRace(t *testing.T) { - c := newGauge("my_gauge", nil, nil) + c := newGauge("my_gauge", nil, nil, nil) end := make(chan struct{}) @@ -240,7 +240,7 @@ func Test_gauge_concurrencyDataRace(t *testing.T) { } func Test_gauge_concurrencyCorrectness(t *testing.T) { - c := newGauge("my_gauge", nil, nil) + c := newGauge("my_gauge", nil, nil, nil) var wg sync.WaitGroup end := make(chan struct{}) diff --git a/modules/generator/registry/registry.go b/modules/generator/registry/registry.go index d7fca905032..4a5ea1725d6 100644 --- a/modules/generator/registry/registry.go +++ b/modules/generator/registry/registry.go @@ -166,7 +166,7 @@ func (r *ManagedRegistry) NewHistogram(name string, buckets []float64, histogram } func (r *ManagedRegistry) NewGauge(name string) Gauge { - g := newGauge(name, r.onAddMetricSeries, r.onRemoveMetricSeries) + g := newGauge(name, r.onAddMetricSeries, r.onRemoveMetricSeries, r.externalLabels) r.registerMetric(g) return g }