-
-
Notifications
You must be signed in to change notification settings - Fork 90
Expand file tree
/
Copy pathmetric_snapshot_df.py
More file actions
110 lines (91 loc) · 4.92 KB
/
metric_snapshot_df.py
File metadata and controls
110 lines (91 loc) · 4.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""A pandas.DataFrame subclass for Prometheus query response."""
try:
from pandas import DataFrame, to_datetime
from pandas._typing import Axes, Dtype
except ImportError as e:
raise ImportError(
"Pandas is required for MetricSnapshotDataFrame class. "
"Please install it with: pip install prometheus-api-client[dataframe] "
"or pip install prometheus-api-client[all]"
) from e
from typing import Optional, Sequence
from prometheus_api_client.exceptions import MetricValueConversionError
class MetricSnapshotDataFrame(DataFrame):
"""Subclass to format and represent Prometheus query response as pandas.DataFrame.
Assumes response is either a json or sequence of jsons.
This is different than passing raw list of jsons to pandas.DataFrame in that it
unpacks metric label values, extracts (first or last) timestamp-value pair (if
multiple pairs are retuned), and concats them before passing to the pandas
DataFrame constructor.
Some argument descriptions in this docstring were copied from pandas.core.frame.DataFrame.
:param data: (list|json) A single metric (json with keys "metric" and "values"/"value")
or list of such metrics received from Prometheus as a response to query
:param index: (pandas.Index|array-like) Index to use for resulting dataframe. Will default to
pandas.RangeIndex if no indexing information part of input data and no index provided.
:param columns: (pandas.Index|array-like) Column labels to use for resulting dataframe. Will
default to list of labels + "timestamp" + "value" if not provided.
:param dtype: (dtype) default None. Data type to force. Only a single dtype is allowed. If None, infer.
:param copy: (bool) default False. Copy data from inputs. Only affects DataFrame / 2d ndarray input.
:param ts_values_keep: (str) If several timestamp-value tuples are returned for a given
metric + label config, determine which one to keep. Currently only supports 'first', 'last'.
:param ts_as_datetime: (bool) default True. Convert the timestamps returned by prometheus
from float64 (unix time) to pandas datetime objects. This results in the timestamp column
of the returned dataframe to be of dtype datetime64[ns] instead float64
Example Usage:
.. code-block:: python
prom = PrometheusConnect()
metric_data = prom.get_current_metric_value(metric_name='up', label_config=my_label_config)
metric_df = MetricSnapshotDataFrame(metric_data)
metric_df.head()
'''
+-------------------------+-----------------+------------+-------+
| __name__ | cluster | label_2 | timestamp | value |
+==========+==============+=================+============+=======+
| up | cluster_id_0 | label_2_value_2 | 1577836800 | 0 |
+-------------------------+-----------------+------------+-------+
| up | cluster_id_1 | label_2_value_3 | 1577836800 | 1 |
+-------------------------+-----------------+------------+-------+
'''
"""
def __init__(
self,
data=None,
index: Optional[Axes] = None,
columns: Optional[Axes] = None,
dtype: Optional[Dtype] = None,
copy: bool = False,
ts_values_keep: str = "last",
ts_as_datetime: bool = True,
):
"""Functions as a constructor for MetricSnapshotDataFrame class."""
if data is not None:
# if just a single json instead of list/set/other sequence of jsons,
# treat as list with single entry
if not isinstance(data, Sequence):
data = [data]
if ts_values_keep not in ("first", "last"):
raise ValueError("ts_values_keep must be one of 'first' and 'last'")
# index corresponding to which ts-value pair to extract
n = -1 if ts_values_keep == "last" else 0
# unpack metric, extract and unpack ts-value pair
data = [
{**i["metric"], **MetricSnapshotDataFrame._get_nth_ts_value_pair(i, n)}
for i in data
]
# init df normally now
super(MetricSnapshotDataFrame, self).__init__(
data=data, index=index, columns=columns, dtype=dtype, copy=copy
)
# convert to DateTime type instead of Float64
if ts_as_datetime:
self["timestamp"] = to_datetime(self["timestamp"], unit="s")
@staticmethod
def _get_nth_ts_value_pair(i: dict, n: int):
val = i["values"][n] if "values" in i else i["value"]
value = val[1]
if isinstance(value, str):
try:
value = float(value)
except (TypeError, ValueError):
raise MetricValueConversionError("Converting string metric value to float failed.")
return {"timestamp": val[0], "value": value}