Repository: prometheus/client_python
Pull request #483 (2019-10-26 15:32:51)

Add support for parsing timestamps.
Closes: https://github.com/prometheus/client_python/issues/461


Patch:
diff --git a/prometheus_client/parser.py b/prometheus_client/parser.py
index d3c7832..1b4373e 100644
--- a/prometheus_client/parser.py
+++ b/prometheus_client/parser.py
@@ -103,15 +103,17 @@ def _parse_labels(labels_string):
 
 
 # If we have multiple values only consider the first
-def _parse_value(s):
+def _parse_value_and_timestamp(s):
     s = s.lstrip()
     separator = " "
     if separator not in s:
         separator = "\t"
-    i = s.find(separator)
-    if i == -1:
-        return s
-    return s[:i]
+    values = [value.strip() for value in s.split(separator) if value.strip()]
+    if not values:
+        return float(s), None
+    value = float(values[0])
+    timestamp = (float(values[-1])/1000) if len(values) > 1 else None
+    return value, timestamp
 
 
 def _parse_sample(text):
@@ -123,8 +125,8 @@ def _parse_sample(text):
         # We ignore the starting curly brace
         label = text[label_start + 1:label_end]
         # The value is after the label end (ignoring curly brace and space)
-        value = float(_parse_value(text[label_end + 2:]))
-        return Sample(name, _parse_labels(label), value)
+        value, timestamp = _parse_value_and_timestamp(text[label_end + 2:])
+        return Sample(name, _parse_labels(label), value, timestamp)
 
     # We don't have labels
     except ValueError:
@@ -135,8 +137,8 @@ def _parse_sample(text):
         name_end = text.index(separator)
         name = text[:name_end]
         # The value is after the name
-        value = float(_parse_value(text[name_end:]))
-        return Sample(name, {}, value)
+        value, timestamp = _parse_value_and_timestamp(text[name_end:])
+        return Sample(name, {}, value, timestamp)
 
 
 def text_fd_to_metric_families(fd):
diff --git a/setup.py b/setup.py
index 90046a4..012fcc9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,13 @@
 from setuptools import setup
+import sys
+from os import path
+
+if sys.version_info >= (2, 7):
+    with open(path.join(path.abspath(path.dirname(__file__)), 'README.md')) as f:
+        long_description = f.read()
+else: # Assuming we don't run setup in order to publish under python 2.6
+    long_description = "NA"
+
 
 setup(
     name="prometheus_client",
@@ -6,9 +15,8 @@ setup(
     author="Brian Brazil",
     author_email="brian.brazil@robustperception.io",
     description="Python client for the Prometheus monitoring system.",
-    long_description=(
-        "See https://github.com/prometheus/client_python/blob/master/README.md"
-        " for documentation."),
+    long_description=long_description,
+    long_description_content_type='text/markdown',
     license="Apache Software License 2.0",
     keywords="prometheus monitoring instrumentation client",
     url="https://github.com/prometheus/client_python",
diff --git a/tox.ini b/tox.ini
index 1a38674..a849cd9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -58,9 +58,9 @@ commands =
 
 [testenv:flake8]
 deps =
-    flake8==3.5.0
-    flake8-docstrings==1.3.0
-    flake8-import-order==0.16
+    flake8==3.7.8
+    flake8-docstrings==1.5.0
+    flake8-import-order==0.18.1
 skip_install = true
 commands =
     flake8 prometheus_client/ tests/ setup.py


Test patch:
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 0c936ba..44a3fa4 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -273,17 +273,20 @@ a{foo="b\\\\a\\z"} 2
         metric_family.add_metric(["b\\a\\z"], 2)
         self.assertEqualMetrics([metric_family], list(families))
 
-    def test_timestamps_discarded(self):
+    def test_timestamps(self):
         families = text_string_to_metric_families("""# TYPE a counter
 # HELP a help
 a{foo="bar"} 1\t000
 # TYPE b counter
 # HELP b help
 b 2  1234567890
+b 88   1234566000   
 """)
         a = CounterMetricFamily("a", "help", labels=["foo"])
-        a.add_metric(["bar"], 1)
-        b = CounterMetricFamily("b", "help", value=2)
+        a.add_metric(["bar"], 1, timestamp=0)
+        b = CounterMetricFamily("b", "help")
+        b.add_metric([], 2, timestamp=1234567.89)
+        b.add_metric([], 88, timestamp=1234566)
         self.assertEqualMetrics([a, b], list(families))
 
     @unittest.skipIf(sys.version_info < (2, 7), "Test requires Python 2.7+.")