16
16
17
17
# In case of a connection failure try 2 more times
18
18
MAX_REQUEST_RETRIES = 3
19
- CONNECTION_RETRY_WAIT_TIME = 1000 # wait 1 second before retrying in case of an error
19
+ # wait 1 second before retrying in case of an error
20
+ CONNECTION_RETRY_WAIT_TIME = 1000
21
+
20
22
21
23
class PrometheusConnect :
22
24
"""
23
25
A Class for collection of metrics from a Prometheus Host
24
26
25
27
:param url: (str) url for the prometheus host
26
- :param headers: (dict) A dictionary of http headers to be used to communicate with the host.
27
- Example: {"Authorization": "bearer my_oauth_token_to_the_host"}
28
+ :param headers: (dict) A dictionary of http headers to be used to communicate with
29
+ the host. Example: {"Authorization": "bearer my_oauth_token_to_the_host"}
28
30
:param disable_ssl: (bool) If set to True, will disable ssl certificate verification
29
- for the http requests made to the prometheus host
30
-
31
+ for the http requests made to the prometheus host
31
32
"""
32
- def __init__ (self , url = 'http://127.0.0.1:9090' , headers = None , disable_ssl = False ):
33
+
34
+ def __init__ (self , url : str = 'http://127.0.0.1:9090' ,
35
+ headers : dict = None , disable_ssl : bool = False ):
33
36
"""
34
37
Constructor for the class PrometheusConnect
35
-
36
38
"""
37
39
self .headers = headers
38
40
self .url = url
39
41
self .prometheus_host = urlparse (self .url ).netloc
40
42
self ._all_metrics = None
41
43
self .ssl_verification = (not disable_ssl )
42
44
43
- @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
44
- def all_metrics (self ):
45
+ @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES ,
46
+ wait_fixed = CONNECTION_RETRY_WAIT_TIME )
47
+ def all_metrics (self , params : dict = None ):
45
48
"""
46
49
Get the list of all the metrics that the prometheus host scrapes
47
50
48
- :return: (list) A list of names of all the metrics available from the
49
- specified prometheus host
50
-
51
+ :param params: (dict) Optional dictionary containing GET parameters to be
52
+ sent along with the API request, such as "time"
53
+ :returns: (list) A list of names of all the metrics available from the
54
+ specified prometheus host
51
55
:raises: (Http Response error) Raises an exception in case of a connection error
52
-
53
56
"""
57
+ params = params or {}
54
58
response = requests .get ('{0}/api/v1/label/__name__/values' .format (self .url ),
55
59
verify = self .ssl_verification ,
56
- headers = self .headers )
60
+ headers = self .headers ,
61
+ params = params ,)
57
62
58
63
if response .status_code == 200 :
59
64
self ._all_metrics = response .json ()['data' ]
@@ -64,18 +69,20 @@ def all_metrics(self):
64
69
))
65
70
return self ._all_metrics
66
71
67
- @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
68
- def get_current_metric_value (self , metric_name , label_config = None ):
72
+ @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES ,
73
+ wait_fixed = CONNECTION_RETRY_WAIT_TIME )
74
+ def get_current_metric_value (
75
+ self , metric_name : str , label_config : dict = None , params : dict = None ):
69
76
"""
70
77
A method to get the current metric value for the specified metric
71
78
and label configuration.
72
79
73
80
:param metric_name: (str) The name of the metric
74
-
75
- :param label_config: (dict) A dictionary that specifies metric labels and their values
76
-
77
- :return: (list) A list of current metric values for the specified metric
78
-
81
+ :param label_config: (dict) A dictionary that specifies metric labels and their
82
+ values
83
+ :param params: (dict) Optional dictionary containing GET parameters to be sent
84
+ along with the API request, such as "time"
85
+ :returns: (list) A list of current metric values for the specified metric
79
86
:raises: (Http Response error) Raises an exception in case of a connection error
80
87
81
88
Example Usage:
@@ -84,19 +91,20 @@ def get_current_metric_value(self, metric_name, label_config=None):
84
91
``my_label_config = {'cluster': 'my_cluster_id', 'label_2': 'label_2_value'}``
85
92
86
93
``prom.get_current_metric_value(metric_name='up', label_config=my_label_config)``
87
-
88
94
"""
95
+ params = params or {}
89
96
data = []
90
97
if label_config :
91
- label_list = [str (key + "=" + "'" + label_config [key ]+ "'" ) for key in label_config ]
98
+ label_list = [str (key + "=" + "'" + label_config [key ] + "'" )
99
+ for key in label_config ]
92
100
# print(label_list)
93
101
query = metric_name + "{" + "," .join (label_list ) + "}"
94
102
else :
95
103
query = metric_name
96
104
97
105
# using the query API to get raw data
98
106
response = requests .get ('{0}/api/v1/query' .format (self .url ),
99
- params = {' query' : query },
107
+ params = {** { " query" : query }, ** params },
100
108
verify = self .ssl_verification ,
101
109
headers = self .headers )
102
110
@@ -109,38 +117,37 @@ def get_current_metric_value(self, metric_name, label_config=None):
109
117
))
110
118
return data
111
119
112
- @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
120
+ @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES ,
121
+ wait_fixed = CONNECTION_RETRY_WAIT_TIME )
113
122
def get_metric_range_data (self ,
114
- metric_name ,
115
- label_config = None ,
116
- start_time = '10m' ,
117
- end_time = 'now' ,
118
- chunk_size = None ,
119
- store_locally = False ):
123
+ metric_name : str ,
124
+ label_config : dict = None ,
125
+ start_time : str = '10m' ,
126
+ end_time : str = 'now' ,
127
+ chunk_size : str = None ,
128
+ store_locally : bool = False ,
129
+ params : dict = None ):
120
130
"""
121
131
A method to get the current metric value for the specified metric
122
132
and label configuration.
123
133
124
134
:param metric_name: (str) The name of the metric.
125
-
126
- :param label_config: (dict) A dictionary that specifies metric labels and their values.
127
-
135
+ :param label_config: (dict) A dictionary specifying metric labels and their
136
+ values.
128
137
:param start_time: (str) A string that specifies the metric range start time.
129
-
130
138
:param end_time: (str) A string that specifies the metric range end time.
131
-
132
- :param chunk_size: (str) Duration of metric data downloaded in one request.
133
- example, setting it to '3h' will download 3 hours
134
- worth of data in each request made to the prometheus host
139
+ :param chunk_size: (str) Duration of metric data downloaded in one request. For
140
+ example, setting it to '3h' will download 3 hours worth of data in each
141
+ request made to the prometheus host
135
142
:param store_locally: (bool) If set to True, will store data locally at,
136
- `"./metrics/hostname/metric_date/name_time.json.bz2"`
137
-
138
- :return: (list) A list of metric data for the specified metric in the given time range
139
-
140
- :raises: (Http Response error) Raises an exception in case of a connection error
141
-
143
+ `"./metrics/hostname/metric_date/name_time.json.bz2"`
144
+ :param params: (dict) Optional dictionary containing GET parameters to be
145
+ sent along with the API request, such as " time"
146
+ :return: (list) A list of metric data for the specified metric in the given time
147
+ range
148
+ :raises: (Exception) Raises an exception in case of a connection error
142
149
"""
143
-
150
+ params = params or {}
144
151
data = []
145
152
146
153
start = int (dateparser .parse (str (start_time )).timestamp ())
@@ -152,13 +159,14 @@ def get_metric_range_data(self,
152
159
else :
153
160
chunk_seconds = (int (round ((dateparser .parse ('now' ) -
154
161
dateparser .parse (chunk_size )
155
- ).total_seconds ())))
162
+ ).total_seconds ())))
156
163
157
- if int (end - start ) < chunk_seconds :
164
+ if int (end - start ) < chunk_seconds :
158
165
sys .exit ("specified chunk_size is too big" )
159
166
160
167
if label_config :
161
- label_list = [str (key + "=" + "'" + label_config [key ]+ "'" ) for key in label_config ]
168
+ label_list = [str (key + "=" + "'" + label_config [key ] + "'" )
169
+ for key in label_config ]
162
170
# print(label_list)
163
171
query = metric_name + "{" + "," .join (label_list ) + "}"
164
172
else :
@@ -167,9 +175,9 @@ def get_metric_range_data(self,
167
175
while start < end :
168
176
# using the query API to get raw data
169
177
response = requests .get ('{0}/api/v1/query' .format (self .url ),
170
- params = {'query' : query + '[' + chunk_size + ']' ,
171
- 'time' : start + chunk_seconds
172
- },
178
+ params = {** { 'query' : query + '[' + chunk_size + ']' ,
179
+ 'time' : start + chunk_seconds
180
+ }, ** params },
173
181
verify = self .ssl_verification ,
174
182
headers = self .headers )
175
183
if response .status_code == 200 :
@@ -182,17 +190,24 @@ def get_metric_range_data(self,
182
190
if store_locally :
183
191
# store it locally
184
192
self ._store_metric_values_local (metric_name ,
185
- json .dumps (response .json ()['data' ]['result' ]),
193
+ json .dumps (
194
+ response .json ()['data' ]['result' ]),
186
195
start + chunk_seconds )
187
196
188
197
start += chunk_seconds
189
198
return data
190
199
191
- def _store_metric_values_local (self , metric_name , values , end_timestamp , compressed = False ):
192
- '''
193
- Method to store metrics locally
200
+ def _store_metric_values_local (
201
+ self , metric_name , values , end_timestamp , compressed = False ):
202
+ """
203
+ Store metrics on the local filesystem, optionally with bz2 compression
194
204
195
- '''
205
+ :param metric_name: (str) the name of the metric being saved
206
+ :param values: (str) metric data in JSON string format
207
+ :param end_timestamp: (str) timestamp in any format understood by dateparser
208
+ :param compressed: (bool) whether or not to apply bz2 compression
209
+ :returns: (str) path to the saved metric file
210
+ """
196
211
if not values :
197
212
_LOGGER .debug ("No values for %s" , metric_name )
198
213
return None
@@ -211,37 +226,38 @@ def _store_metric_values_local(self, metric_name, values, end_timestamp, compres
211
226
212
227
return file_path
213
228
214
- def _metric_filename (self , metric_name , end_timestamp ):
215
- '''
229
+ def _metric_filename (self , metric_name : str , end_timestamp : str ):
230
+ """
216
231
Adds a timestamp to the filename before it is stored
217
232
218
- '''
233
+ :param metric_name: (str) the name of the metric being saved
234
+ :param end_timestamp: (str) timestamp in any format understood by dateparser
235
+ :returns: (str) the generated path
236
+ """
219
237
end_timestamp = dateparser .parse (str (end_timestamp ))
220
238
directory_name = end_timestamp .strftime ("%Y%m%d" )
221
239
timestamp = end_timestamp .strftime ("%Y%m%d%H%M" )
222
240
object_path = "./metrics/" + self .prometheus_host + "/" + \
223
- metric_name + "/" + directory_name + "/" + timestamp + ".json"
241
+ metric_name + "/" + directory_name + "/" + timestamp + ".json"
224
242
return object_path
225
243
226
- @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
227
- def custom_query (self , query : str , params : dict = {}):
244
+ @retry (stop_max_attempt_number = MAX_REQUEST_RETRIES ,
245
+ wait_fixed = CONNECTION_RETRY_WAIT_TIME )
246
+ def custom_query (self , query : str , params : dict = None ):
228
247
"""
229
248
A method to send a custom query to a Prometheus Host.
230
249
231
250
This method takes as input a string which will be sent as a query to
232
251
the specified Prometheus Host. This query is a PromQL query.
233
252
234
253
:param query: (str) This is a PromQL query, a few examples can be found
235
- at https://prometheus.io/docs/prometheus/latest/querying/examples/
236
-
254
+ at https://prometheus.io/docs/prometheus/latest/querying/examples/
237
255
:param params: (dict) Optional dictionary containing GET parameters to be
238
- sent along with the API request, such as "time"
239
-
240
- :Returns: (list) A list of metric data received in response of the query sent
241
-
242
- :raises: (Http Response error) Raises an exception in case of a connection error
243
-
256
+ sent along with the API request, such as "time"
257
+ :returns: (list) A list of metric data received in response of the query sent
258
+ :raises: (Exception) Raises an exception in case of a connection error
244
259
"""
260
+ params = params or {}
245
261
data = None
246
262
query = str (query )
247
263
# using the query API to get raw data
@@ -261,13 +277,13 @@ def custom_query(self, query: str, params: dict = {}):
261
277
262
278
return data
263
279
280
+
264
281
def pretty_print_metric (metric_data ):
265
282
"""
266
283
A function to pretty print the metric data downloaded using class PrometheusConnect.
267
284
268
285
:param metric_data: (list) This is the metric data list returned from methods
269
- get_metric_range_data and get_current_metric_value
270
-
286
+ get_metric_range_data and get_current_metric_value
271
287
"""
272
288
data = metric_data
273
289
for metric in data :
0 commit comments