Skip to content

Commit

Permalink
Update canonical floats per openmetrics latest. (#538)
Browse files Browse the repository at this point in the history
We now only require a specific set of very common le/quantile
labels to be in a canonical form.

Signed-off-by: Brian Brazil <brian.brazil@robustperception.io>
  • Loading branch information
brian-brazil authored May 20, 2020
1 parent 3be4faf commit cfc67a5
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 13 deletions.
15 changes: 12 additions & 3 deletions prometheus_client/openmetrics/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
# Python 3
import io as StringIO


def text_string_to_metric_families(text):
"""Parse Openmetrics text format from a unicode string.
Expand All @@ -25,6 +24,16 @@ def text_string_to_metric_families(text):
yield metric_family


_CANONICAL_NUMBERS = set([i / 1000.0 for i in range(10000)] + [10.0**i for i in range(-10, 11)] + [float("inf")])


def _isUncanonicalNumber(s):
f = float(s)
if f not in _CANONICAL_NUMBERS:
return False # Only the canonical numbers are required to be canonical.
return s != floatToGoString(f)


ESCAPE_SEQUENCES = {
'\\\\': '\\',
'\\n': '\n',
Expand Down Expand Up @@ -544,11 +553,11 @@ def build_metric(name, documentation, typ, unit, samples):
raise ValueError("Stateset missing label: " + line)
if (typ in ['histogram', 'gaugehistogram'] and name + '_bucket' == sample.name
and (sample.labels.get('le', "NaN") == "NaN"
or sample.labels['le'] != floatToGoString(sample.labels['le']))):
or _isUncanonicalNumber(sample.labels['le']))):
raise ValueError("Invalid le label: " + line)
if (typ == 'summary' and name == sample.name
and (not (0 <= float(sample.labels.get('quantile', -1)) <= 1)
or sample.labels['quantile'] != floatToGoString(sample.labels['quantile']))):
or _isUncanonicalNumber(sample.labels['quantile']))):
raise ValueError("Invalid quantile label: " + line)

g = tuple(sorted(_group_for_sample(sample, name, typ).items()))
Expand Down
28 changes: 18 additions & 10 deletions tests/openmetrics/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ def test_simple_histogram(self):
self.assertEqual([HistogramMetricFamily("a", "help", sum_value=2, buckets=[("1.0", 0.0), ("+Inf", 3.0)])],
list(families))

def test_histogram_noncanonical(self):
families = text_string_to_metric_families("""# TYPE a histogram
# HELP a help
a_bucket{le="0.00000000001"} 0
a_bucket{le="1.1e-4"} 0
a_bucket{le="1.1e-3"} 0
a_bucket{le="100000000000.0"} 0
a_bucket{le="+Inf"} 3
a_count 3
a_sum 2
# EOF
""")
list(families)

def test_negative_bucket_histogram(self):
families = text_string_to_metric_families("""# TYPE a histogram
# HELP a help
Expand Down Expand Up @@ -731,9 +745,13 @@ def test_invalid_input(self):
('# TYPE a gaugehistogram\na_gsum 1\n# EOF\n'),
('# TYPE a histogram\na_count 1\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+Inf"} 0\na_count 1\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="0"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="0.0000000001"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1.1e-2"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1e-04"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1e+05"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="10000000000"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="+INF"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="2"} 0\na_bucket{le="1"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1"} 1\na_bucket{le="2"} 1\na_bucket{le="+Inf"} 0\n# EOF\n'),
Expand All @@ -754,16 +772,6 @@ def test_invalid_input(self):
with self.assertRaises(ValueError, msg=case):
list(text_string_to_metric_families(case))

@unittest.skipIf(sys.version_info < (2, 7), "float repr changed from 2.6 to 2.7")
def test_invalid_float_input(self):
for case in [
# Bad histograms.
('# TYPE a histogram\na_bucket{le="9.999999999999999e+22"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
('# TYPE a histogram\na_bucket{le="1.5555555555555201e+06"} 0\na_bucket{le="+Inf"} 0\n# EOF\n'),
]:
with self.assertRaises(ValueError):
list(text_string_to_metric_families(case))


if __name__ == '__main__':
unittest.main()

0 comments on commit cfc67a5

Please sign in to comment.