Repository: prometheus/client_python
Pull request #338 (2018-11-05 13:41:28)

Check for negative counter-like and guage histogram values.
@SuperQ per the last two meetings.


Patch:
diff --git a/prometheus_client/openmetrics/parser.py b/prometheus_client/openmetrics/parser.py
index 5ddcd26..dcea755 100644
--- a/prometheus_client/openmetrics/parser.py
+++ b/prometheus_client/openmetrics/parser.py
@@ -433,8 +433,12 @@ def text_fd_to_metric_families(fd):
                 raise ValueError("Stateset samples can only have values zero and one: " + line)
             if typ == 'info' and sample.value != 1:
                 raise ValueError("Info samples can only have value one: " + line)
-            if sample.name[len(name):] in ['_total', '_sum', '_count', '_bucket'] and math.isnan(sample.value):
+            if typ == 'summary' and name == sample.name and sample.value < 0:
+                raise ValueError("Quantile values cannot be negative: " + line)
+            if sample.name[len(name):] in ['_total', '_sum', '_count', '_bucket', '_gcount', '_gsum'] and math.isnan(sample.value):
                 raise ValueError("Counter-like samples cannot be NaN: " + line)
+            if sample.name[len(name):] in ['_total', '_sum', '_count', '_bucket', '_gcount', '_gsum'] and sample.value < 0:
+                raise ValueError("Counter-like samples cannot be negative: " + line)
             if sample.exemplar and not (
                     typ in ['histogram', 'gaugehistogram']
                     and sample.name.endswith('_bucket')):


Test patch:
diff --git a/tests/openmetrics/test_parser.py b/tests/openmetrics/test_parser.py
index 681cfe3..092d8d3 100644
--- a/tests/openmetrics/test_parser.py
+++ b/tests/openmetrics/test_parser.py
@@ -248,13 +248,13 @@ a_total 1
         self.assertEqual([CounterMetricFamily("a", "", value=1)], list(families))
 
     def test_labels_and_infinite(self):
-        families = text_string_to_metric_families("""# TYPE a counter
+        families = text_string_to_metric_families("""# TYPE a gauge
 # HELP a help
-a_total{foo="bar"} +Inf
-a_total{foo="baz"} -Inf
+a{foo="bar"} +Inf
+a{foo="baz"} -Inf
 # EOF
 """)
-        metric_family = CounterMetricFamily("a", "help", labels=["foo"])
+        metric_family = GaugeMetricFamily("a", "help", labels=["foo"])
         metric_family.add_metric(["bar"], float('inf'))
         metric_family.add_metric(["baz"], float('-inf'))
         self.assertEqual([metric_family], list(families))
@@ -527,12 +527,23 @@ prometheus_local_storage_chunk_ops_total{type="unpin"} 32662.0
                 ('# TYPE a stateset\na 0\n# EOF\n'),
                 # Bad counter values.
                 ('# TYPE a counter\na_total NaN\n# EOF\n'),
+                ('# TYPE a counter\na_total -1\n# EOF\n'),
                 ('# TYPE a histogram\na_sum NaN\n# EOF\n'),
                 ('# TYPE a histogram\na_count NaN\n# EOF\n'),
                 ('# TYPE a histogram\na_bucket{le="+Inf"} NaN\n# EOF\n'),
+                ('# TYPE a histogram\na_sum -1\n# EOF\n'),
+                ('# TYPE a histogram\na_count -1\n# EOF\n'),
+                ('# TYPE a histogram\na_bucket{le="+Inf"} -1\n# EOF\n'),
                 ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} NaN\n# EOF\n'),
+                ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} -1\na_gcount -1\n# EOF\n'),
+                ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} -1\n# EOF\n'),
+                ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} 1\na_gsum -1\n# EOF\n'),
+                ('# TYPE a gaugehistogram\na_bucket{le="+Inf"} 1\na_gsum NaN\n# EOF\n'),
                 ('# TYPE a summary\na_sum NaN\n# EOF\n'),
                 ('# TYPE a summary\na_count NaN\n# EOF\n'),
+                ('# TYPE a summary\na_sum -1\n# EOF\n'),
+                ('# TYPE a summary\na_count -1\n# EOF\n'),
+                ('# TYPE a summary\na{quantile="0.5"} -1\n# EOF\n'),
                 # Bad histograms.
                 ('# TYPE a histogram\na_sum 1\n# EOF\n'),
                 ('# TYPE a gaugehistogram\na_gsum 1\n# EOF\n'),