Repository: prometheus/client_python
Pull request #642 (2021-04-01 09:08:58)

Add a clear() method to metric objects to remove all labelsets
Hello @brian-brazil, 

I wanted to test metric values in my application unit tests but I didn't figured out how to do it (I probably missed something). That's why I propose to add this simple `reset()` method. Do you think it can be useful? Or is there a better way to test than reseting metrics at the beginning of the test?

And thank you for this very useful lib!

Veknelyon: It does not work in my case because my metrics are global variables shared in my code. So changing the registry does not reset values stored in the metric.
Here is a simplification of my code:

```python
from prometheus_client import Counter, CollectorRegistry, REGISTRY
from pytest import fixture

RUN_COUNTER = Counter('connector_run', labelnames=['tenant'])


def my_function():
    RUN_COUNTER.labels('tenantid').inc()
    # do things


@fixture
def metric_registry():
    registry = CollectorRegistry()
    registry.register(RUN_COUNTER)
    return registry


def test1(metric_registry):
    my_function()
    
    # other asserts


def test2(metric_registry):
    my_function()

    run_count = metric_registry.get_sample_value('connector_run_total', labels={'tenant': 'tenantid'})
    assert run_count == 1.0
```

(the code is not as simple so I need to keep `test1` and `test2` separated)

When I run this code `assert run_count == 1.0` failed because `test1` is executed first (and I can't presume test execution order).

My issue come from the fact that this is not the registry which store the metric value but `RUN_COUNTER` which is global.
With the `reset()` method, I would be able to write:

```python
@fixture
def metric_registry():
    RUN_COUNTER.reset()
    registry = CollectorRegistry()
    registry.register(RUN_COUNTER)
    return registry
```

Patch:
diff --git a/prometheus_client/metrics.py b/prometheus_client/metrics.py
index 95770eb..aea8832 100644
--- a/prometheus_client/metrics.py
+++ b/prometheus_client/metrics.py
@@ -186,6 +186,11 @@ class MetricWrapperBase(object):
         with self._lock:
             del self._metrics[labelvalues]
 
+    def clear(self):
+        """Remove all labelsets from the metric"""
+        with self._lock:
+            self._metrics = {}
+
     def _samples(self):
         if self._is_parent():
             return self._multi_samples()


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 5a81f12..55c88b7 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -456,6 +456,15 @@ class TestMetricWrapper(unittest.TestCase):
         self.assertEqual(None, self.registry.get_sample_value('c_total', {'l': 'x'}))
         self.assertEqual(2, self.registry.get_sample_value('c_total', {'l': 'y'}))
 
+    def test_clear(self):
+        self.counter.labels('x').inc()
+        self.counter.labels('y').inc(2)
+        self.assertEqual(1, self.registry.get_sample_value('c_total', {'l': 'x'}))
+        self.assertEqual(2, self.registry.get_sample_value('c_total', {'l': 'y'}))
+        self.counter.clear()
+        self.assertEqual(None, self.registry.get_sample_value('c_total', {'l': 'x'}))
+        self.assertEqual(None, self.registry.get_sample_value('c_total', {'l': 'y'}))
+
     def test_incorrect_label_count_raises(self):
         self.assertRaises(ValueError, self.counter.labels)
         self.assertRaises(ValueError, self.counter.labels, 'a', 'b')