diff --git a/prometheus/vec.go b/prometheus/vec.go index ab715b83c..56172de4a 100644 --- a/prometheus/vec.go +++ b/prometheus/vec.go @@ -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) } @@ -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) } @@ -374,10 +374,12 @@ 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) { @@ -385,10 +387,10 @@ func (m *metricMap) deleteByLabelValues(lvs []string) bool { continue } delete(m.metrics, h) - return true + numDeleted++ } - return false + return numDeleted } // findMetricWithPartialLabelValues returns the index of the matching metric or @@ -445,10 +447,12 @@ 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) { @@ -456,10 +460,10 @@ func (m *metricMap) deleteByLabels(labels Labels) bool { continue } delete(m.metrics, h) - return true + numDeleted++ } - return false + return numDeleted } // findMetricWithPartialLabel returns the index of the matching metric or diff --git a/prometheus/vec_test.go b/prometheus/vec_test.go index 9391fded8..67c4f60ea 100644 --- a/prometheus/vec_test.go +++ b/prometheus/vec_test.go @@ -138,7 +138,7 @@ 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) } @@ -146,25 +146,39 @@ func testDeletePartialMatch(t *testing.T, vec *GaugeVec) { 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) } } @@ -182,19 +196,26 @@ 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) } @@ -202,12 +223,12 @@ func testDeletePartialMatchLabelValues(t *testing.T, vec *GaugeVec) { 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) } }