1
+ """
2
+ A Class for collection of metrics from a Prometheus Host.
3
+ """
1
4
from urllib .parse import urlparse
2
- import requests
3
- import datetime
5
+ import bz2
6
+ import os
7
+ import sys
4
8
import json
5
- import time
9
+ import logging
10
+ import requests
6
11
import dateparser
7
- import sys
8
- import os
9
12
from retrying import retry
10
- import bz2
11
13
12
14
# set up logging
13
- import logging
14
15
_LOGGER = logging .getLogger (__name__ )
15
16
16
- # Disable SSL warnings
17
- from requests .packages .urllib3 .exceptions import InsecureRequestWarning
18
- requests .packages .urllib3 .disable_warnings (InsecureRequestWarning )
19
-
20
17
DEBUG = False
21
18
MAX_REQUEST_RETRIES = 3
22
19
CONNECTION_RETRY_WAIT_TIME = 1000 # wait 1 second before retrying in case of an error
23
20
24
21
class PrometheusConnect :
25
- """docstring for Prometheus."""
26
- def __init__ (self , url = '127.0.0.1:9090' , token = None ):
27
- self .headers = { 'Authorization' : "bearer {}" .format (token ) }
22
+ """
23
+ A Class for collection of metrics from a Prometheus Host.
24
+ """
25
+ def __init__ (self , url = 'http://127.0.0.1:9090' , headers = None , disable_ssl = False ):
26
+ """
27
+ A short description.
28
+
29
+ A bit longer description.
30
+
31
+ Args:
32
+ url (str): url for the prometheus host
33
+ headers (dict): A dictionary of http headers to be used to communicate with the host.
34
+ Example: {'Authorization': "bearer my_oauth_token_to_the_host"}
35
+ disable_ssl (bool): If set to True, will disable ssl certificate verification
36
+ for the http requests made to the prometheus host
37
+ """
38
+ self .headers = headers
28
39
self .url = url
29
40
self .prometheus_host = urlparse (self .url ).netloc
30
41
self ._all_metrics = None
42
+ self .ssl_verification = (not disable_ssl )
31
43
32
44
@retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
33
45
def all_metrics (self ):
34
- '''
46
+ """
35
47
Get the list of all the metrics that the prometheus host has
36
- '''
48
+
49
+ Returns:
50
+ list: list of names of all the metrics available from the specified prometheus host
51
+
52
+ Raises:
53
+ Exception: description
54
+
55
+ """
56
+
37
57
response = requests .get ('{0}/api/v1/label/__name__/values' .format (self .url ),
38
- verify = False , # Disable ssl certificate verification temporarily
58
+ verify = self . ssl_verification ,
39
59
headers = self .headers )
40
60
41
61
if response .status_code == 200 :
42
62
self ._all_metrics = response .json ()['data' ]
43
63
else :
44
- raise Exception ("HTTP Status Code {} {} ({})" .format (
64
+ raise Exception ("HTTP Status Code {} ({})" .format (
45
65
response .status_code ,
46
- requests .status_codes ._codes [response .status_code ][0 ],
47
66
response .content
48
67
))
49
68
return self ._all_metrics
50
69
51
70
@retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
52
- def get_current_metric_value (self , metric_name , label_config = None ):
71
+ def get_current_metric_value (self , metric_name , label_config = None ):
72
+ """
73
+ A method to get the current metric value for the specified metric
74
+ and label configuration.
75
+
76
+ For example:
77
+ prom = PrometheusConnect()
78
+ my_label_config = {'cluster': 'my_cluster_id',
79
+ 'label_2': 'label_2_value'}
80
+ prom.get_current_metric_value(metric_name='up', label_config=my_label_config)
81
+
82
+ Args:
83
+ metric_name (str): The name of the metric
84
+ label_config (dict): A dictionary that specifies metric labels and their values
85
+
86
+ Returns:
87
+ list: A list of current metric data for the specified metric
88
+
89
+ Raises:
90
+ Http Response error: Raises an exception in case of a connection error
91
+
92
+ """
93
+
53
94
data = []
54
95
if label_config :
55
96
label_list = [str (key + "=" + "'" + label_config [key ]+ "'" ) for key in label_config ]
@@ -58,23 +99,57 @@ def get_current_metric_value(self, metric_name, label_config = None):
58
99
else :
59
100
query = metric_name
60
101
61
- response = requests .get ('{0}/api/v1/query' .format (self .url ), # using the query API to get raw data
62
- params = {'query' : query },#label_config},
63
- verify = False , # Disable ssl certificate verification temporarily
102
+ # using the query API to get raw data
103
+ response = requests .get ('{0}/api/v1/query' .format (self .url ),
104
+ params = {'query' : query },
105
+ verify = self .ssl_verification ,
64
106
headers = self .headers )
65
107
66
108
if response .status_code == 200 :
67
109
data += response .json ()['data' ]['result' ]
68
110
else :
69
- raise Exception ("HTTP Status Code {} {} ({})" .format (
111
+ raise Exception ("HTTP Status Code {} ({})" .format (
70
112
response .status_code ,
71
- requests .status_codes ._codes [response .status_code ][0 ],
72
113
response .content
73
114
))
74
- return ( data )
115
+ return data
75
116
76
117
@retry (stop_max_attempt_number = MAX_REQUEST_RETRIES , wait_fixed = CONNECTION_RETRY_WAIT_TIME )
77
- def get_metric_range_data (self , metric_name , start_time , end_time = 'now' , chunk_size = None ,label_config = None , store_locally = False ):
118
+ def get_metric_range_data (self ,
119
+ metric_name ,
120
+ label_config = None ,
121
+ start_time = '10m' ,
122
+ end_time = 'now' ,
123
+ chunk_size = None ,
124
+ store_locally = False ):
125
+ """
126
+ A method to get the current metric value for the specified metric
127
+ and label configuration.
128
+
129
+ For example:
130
+ prom = PrometheusConnect()
131
+ my_label_config = {'cluster': 'my_cluster_id',
132
+ 'label_2': 'label_2_value'}
133
+ prom.get_current_metric_value(metric_name='up', label_config=my_label_config)
134
+
135
+ Args:
136
+ metric_name (str): The name of the metric
137
+ label_config (dict): A dictionary that specifies metric labels and their values
138
+ start_time (str):
139
+ end_time (str):
140
+ chunk_size (str): Duration of metric data downloaded in one request.
141
+ example, setting it to '3h' will download 3 hours
142
+ worth of data in each request made to the prometheus host
143
+ store_locally (bool): If set to True, will store data locally at,
144
+ "./metrics/$(PROMETHEUS_HOST)/$(METRIC_DATE)/$(METRIC_TIMESTAMP).json.bz2"
145
+
146
+ Returns:
147
+ list: A list of metric data for the specified metric in the given time range
148
+
149
+ Raises:
150
+ Http Response error: Raises an exception in case of a connection error
151
+
152
+ """
78
153
data = []
79
154
80
155
start = int (dateparser .parse (str (start_time )).timestamp ())
@@ -84,7 +159,9 @@ def get_metric_range_data(self, metric_name, start_time, end_time='now', chunk_s
84
159
chunk_seconds = int (end - start )
85
160
chunk_size = str (int (chunk_seconds )) + "s"
86
161
else :
87
- chunk_seconds = int (round ((dateparser .parse ('now' ) - dateparser .parse (chunk_size )).total_seconds ()))
162
+ chunk_seconds = (int (round ((dateparser .parse ('now' ) -
163
+ dateparser .parse (chunk_size )
164
+ ).total_seconds ())))
88
165
89
166
if int (end - start ) < chunk_seconds :
90
167
sys .exit ("specified chunk_size is too big" )
@@ -97,37 +174,38 @@ def get_metric_range_data(self, metric_name, start_time, end_time='now', chunk_s
97
174
query = metric_name
98
175
99
176
while start < end :
100
- # print(chunk_size)
101
- response = requests .get ('{0}/api/v1/query' .format (self .url ), # using the query API to get raw data
102
- params = {'query' : query + '[' + chunk_size + ']' ,
103
- 'time' : start + chunk_seconds
104
- },
105
- verify = False , # Disable ssl certificate verification temporarily
106
- headers = self .headers )
177
+ # using the query API to get raw data
178
+ response = requests .get ('{0}/api/v1/query' .format (self .url ),
179
+ params = {'query' : query + '[' + chunk_size + ']' ,
180
+ 'time' : start + chunk_seconds
181
+ },
182
+ verify = self . ssl_verification ,
183
+ headers = self .headers )
107
184
if response .status_code == 200 :
108
185
data += response .json ()['data' ]['result' ]
109
186
else :
110
- raise Exception ("HTTP Status Code {} {} ({})" .format (
187
+ raise Exception ("HTTP Status Code {} ({})" .format (
111
188
response .status_code ,
112
- requests .status_codes ._codes [response .status_code ][0 ],
113
189
response .content
114
190
))
115
191
if store_locally :
116
192
# store it locally
117
- self .store_metric_values_local (metric_name , (response .json ()['data' ]['result' ]), start + chunk_seconds )
193
+ self ._store_metric_values_local (metric_name ,
194
+ json .dumps (response .json ()['data' ]['result' ]),
195
+ start + chunk_seconds )
118
196
119
197
start += chunk_seconds
120
- return ( data )
198
+ return data
121
199
122
- def store_metric_values_local (self , metric_name , values , end_timestamp , file_path = None , compressed = True ):
200
+ def _store_metric_values_local (self , metric_name , values , end_timestamp , compressed = False ):
123
201
'''
124
- Function to store metrics locally
202
+ Method to store metrics locally
125
203
'''
126
204
if not values :
127
- return "No values for {}" .format (metric_name )
205
+ _LOGGER .debug ("No values for %s" , metric_name )
206
+ return None
128
207
129
- if not file_path :
130
- file_path = self ._metric_filename (metric_name , end_timestamp )
208
+ file_path = self ._metric_filename (metric_name , end_timestamp )
131
209
132
210
if compressed :
133
211
payload = bz2 .compress (str (values ).encode ('utf-8' ))
@@ -139,17 +217,28 @@ def store_metric_values_local(self, metric_name, values, end_timestamp, file_pat
139
217
with open (file_path , "wb" ) as file :
140
218
file .write (payload )
141
219
220
+ return file_path
221
+
142
222
def _metric_filename (self , metric_name , end_timestamp ):
143
223
'''
144
224
Adds a timestamp to the filename before it is stored
145
225
'''
146
226
end_timestamp = dateparser .parse (str (end_timestamp ))
147
227
directory_name = end_timestamp .strftime ("%Y%m%d" )
148
228
timestamp = end_timestamp .strftime ("%Y%m%d%H%M" )
149
- object_path = "./metrics/" + self .prometheus_host + "/" + metric_name + "/" + directory_name + "/" + timestamp + ".json"
229
+ object_path = "./metrics/" + self .prometheus_host + "/" + \
230
+ metric_name + "/" + directory_name + "/" + timestamp + ".json"
150
231
return object_path
151
232
152
- def pretty_print_metric (self , metric_data ):
153
- data = metric_data
154
- for metric in data :
155
- print (json .dumps (metric , indent = 4 , sort_keys = True ))
233
+ def pretty_print_metric (metric_data ):
234
+ """
235
+ A function to pretty print the metric data downloaded using class PrometheusConnect.
236
+
237
+ Args:
238
+ metric_data (list): This is the metric data returned from functions
239
+ get_metric_range_data and get_current_metric_value
240
+ """
241
+
242
+ data = metric_data
243
+ for metric in data :
244
+ print (json .dumps (metric , indent = 4 , sort_keys = True ))
0 commit comments