Skip to content

Commit

Permalink
Handle properly deleting multiple metrics, update tests
Browse files Browse the repository at this point in the history
Signed-off-by: Zach Stone <zach@giantswarm.io>
  • Loading branch information
stone-z committed Mar 25, 2022
1 parent 387c4f0 commit fa775cf
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 20 deletions.
24 changes: 14 additions & 10 deletions prometheus/vec.go
Expand Up @@ -82,11 +82,11 @@ func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {

// DeletePartialMatchLabelValues removes the metric where the variable labels
// contain all of the values passed. The order of the passed values does not matter.
// It returns true if a metric was deleted.
// It returns the number of metrics deleted.

// This method deletes a metric if the given value is present for any label.
// To delete a metric based on a partial match for a particular label, use DeletePartialMatch().
func (m *MetricVec) DeletePartialMatchLabelValues(lvs ...string) bool {
func (m *MetricVec) DeletePartialMatchLabelValues(lvs ...string) int {
return m.metricMap.deleteByLabelValues(lvs)
}

Expand All @@ -111,11 +111,11 @@ func (m *MetricVec) Delete(labels Labels) bool {

// DeletePartialMatch deletes the metric where the variable labels contains all of those
// passed in as labels. The order of the labels does not matter.
// It returns true if a metric was deleted.
// It returns the number of metrics deleted.

// This method deletes a metric if the given label: value pair is found in that metric.
// To delete a metric if a particular value is found associated with any label, use DeletePartialMatchLabelValues().
func (m *MetricVec) DeletePartialMatch(labels Labels) bool {
func (m *MetricVec) DeletePartialMatch(labels Labels) int {
return m.metricMap.deleteByLabels(labels)
}

Expand Down Expand Up @@ -374,21 +374,23 @@ func (m *metricMap) deleteByHashWithLabelValues(
}

// deleteByLabelValues deletes a metric if the given values (lvs) are present in the metric.
func (m *metricMap) deleteByLabelValues(lvs []string) bool {
func (m *metricMap) deleteByLabelValues(lvs []string) int {
m.mtx.Lock()
defer m.mtx.Unlock()

var numDeleted int

for h, metrics := range m.metrics {
i := findMetricWithPartialLabelValues(metrics, lvs)
if i >= len(metrics) {
// Didn't find matching label values in this metric slice.
continue
}
delete(m.metrics, h)
return true
numDeleted++
}

return false
return numDeleted
}

// findMetricWithPartialLabelValues returns the index of the matching metric or
Expand Down Expand Up @@ -445,21 +447,23 @@ func (m *metricMap) deleteByHashWithLabels(
}

// deleteByLabels deletes a metric if the given labels are present in the metric.
func (m *metricMap) deleteByLabels(labels Labels) bool {
func (m *metricMap) deleteByLabels(labels Labels) int {
m.mtx.Lock()
defer m.mtx.Unlock()

var numDeleted int

for h, metrics := range m.metrics {
i := findMetricWithPartialLabels(m.desc, metrics, labels)
if i >= len(metrics) {
// Didn't find matching labels in this metric slice.
continue
}
delete(m.metrics, h)
return true
numDeleted++
}

return false
return numDeleted
}

// findMetricWithPartialLabel returns the index of the matching metric or
Expand Down
41 changes: 31 additions & 10 deletions prometheus/vec_test.go
Expand Up @@ -138,33 +138,47 @@ func TestDeletePartialMatch(t *testing.T) {

func testDeletePartialMatch(t *testing.T, vec *GaugeVec) {
// No metric value is set.
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1", "l2": "v2"}), false; got != want {
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1", "l2": "v2"}), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

c1 := vec.MustCurryWith(Labels{"l1": "v1"})
c1.WithLabelValues("2").Inc()

// Try to delete nonexistent label lx with existent value v1.
if got, want := c1.DeletePartialMatch(Labels{"lx": "v1"}), false; got != want {
if got, want := c1.DeletePartialMatch(Labels{"lx": "v1"}), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Delete with valid pair l1: v1.
if got, want := c1.DeletePartialMatch(Labels{"l1": "v1"}), true; got != want {
if got, want := c1.DeletePartialMatch(Labels{"l1": "v1"}), 1; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Try to delete with partially invalid labels.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1", "l2": "xv2"}), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Try to delete with a single valid label which matches multiple metrics.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
vec.With(Labels{"l1": "v1", "l2": "vv22"}).(Gauge).Set(84)
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), 2; got != want {
t.Errorf("got %v, want %v", got, want)
}

c2 := vec.MustCurryWith(Labels{"l2": "l2CurriedValue"})
c2.With(Labels{"l1": "11"}).Inc()

// Delete with valid curried pair l2: l2CurriedValue.
if got, want := c2.DeletePartialMatch(Labels{"l2": "l2CurriedValue"}), true; got != want {
if got, want := c2.DeletePartialMatch(Labels{"l2": "l2CurriedValue"}), 1; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Same labels, value matches.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), true; got != want {
if got, want := vec.DeletePartialMatch(Labels{"l1": "v1"}), 1; got != want {
t.Errorf("got %v, want %v", got, want)
}
}
Expand All @@ -182,32 +196,39 @@ func TestDeletePartialMatchLabelValues(t *testing.T) {

func testDeletePartialMatchLabelValues(t *testing.T, vec *GaugeVec) {
// No metric value is set.
if got, want := vec.DeletePartialMatchLabelValues("v1", "v2"), false; got != want {
if got, want := vec.DeletePartialMatchLabelValues("v1", "v2"), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Try to delete with a single valid value.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
if got, want := vec.DeletePartialMatchLabelValues("v1"), true; got != want {
if got, want := vec.DeletePartialMatchLabelValues("v1"), 1; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Try to delete with partially invalid values.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
if got, want := vec.DeletePartialMatchLabelValues("v1", "xv2"), false; got != want {
if got, want := vec.DeletePartialMatchLabelValues("v1", "xv2"), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Try to delete with a single valid value which matches multiple metrics.
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Gauge).Set(42)
vec.With(Labels{"l1": "v1", "l2": "vv22"}).(Gauge).Set(84)
if got, want := vec.DeletePartialMatchLabelValues("v1"), 2; got != want {
t.Errorf("got %v, want %v", got, want)
}

c1 := vec.MustCurryWith(Labels{"l1": "cv1"})
c1.WithLabelValues("2").Inc()

// Try to delete with nonexistent value z1.
if got, want := c1.DeletePartialMatchLabelValues("z1"), false; got != want {
if got, want := c1.DeletePartialMatchLabelValues("z1"), 0; got != want {
t.Errorf("got %v, want %v", got, want)
}

// Delete with valid curried value cv1.
if got, want := c1.DeletePartialMatchLabelValues("cv1"), true; got != want {
if got, want := c1.DeletePartialMatchLabelValues("cv1"), 1; got != want {
t.Errorf("got %v, want %v", got, want)
}
}
Expand Down

0 comments on commit fa775cf

Please sign in to comment.