Skip to content

Commit 5701a4b

Browse files
author
Anand Sanmukhani
committed
Add documentation for the class and its methods.
1 parent 7dd7b0e commit 5701a4b

File tree

1 file changed

+138
-49
lines changed

1 file changed

+138
-49
lines changed
Lines changed: 138 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,96 @@
1+
"""
2+
A Class for collection of metrics from a Prometheus Host.
3+
"""
14
from urllib.parse import urlparse
2-
import requests
3-
import datetime
5+
import bz2
6+
import os
7+
import sys
48
import json
5-
import time
9+
import logging
10+
import requests
611
import dateparser
7-
import sys
8-
import os
912
from retrying import retry
10-
import bz2
1113

1214
# set up logging
13-
import logging
1415
_LOGGER = logging.getLogger(__name__)
1516

16-
# Disable SSL warnings
17-
from requests.packages.urllib3.exceptions import InsecureRequestWarning
18-
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
19-
2017
DEBUG = False
2118
MAX_REQUEST_RETRIES = 3
2219
CONNECTION_RETRY_WAIT_TIME = 1000 # wait 1 second before retrying in case of an error
2320

2421
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
2839
self.url = url
2940
self.prometheus_host = urlparse(self.url).netloc
3041
self._all_metrics = None
42+
self.ssl_verification = (not disable_ssl)
3143

3244
@retry(stop_max_attempt_number=MAX_REQUEST_RETRIES, wait_fixed=CONNECTION_RETRY_WAIT_TIME)
3345
def all_metrics(self):
34-
'''
46+
"""
3547
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+
3757
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,
3959
headers=self.headers)
4060

4161
if response.status_code == 200:
4262
self._all_metrics = response.json()['data']
4363
else:
44-
raise Exception("HTTP Status Code {} {} ({})".format(
64+
raise Exception("HTTP Status Code {} ({})".format(
4565
response.status_code,
46-
requests.status_codes._codes[response.status_code][0],
4766
response.content
4867
))
4968
return self._all_metrics
5069

5170
@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+
5394
data = []
5495
if label_config:
5596
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):
5899
else:
59100
query = metric_name
60101

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,
64106
headers=self.headers)
65107

66108
if response.status_code == 200:
67109
data += response.json()['data']['result']
68110
else:
69-
raise Exception("HTTP Status Code {} {} ({})".format(
111+
raise Exception("HTTP Status Code {} ({})".format(
70112
response.status_code,
71-
requests.status_codes._codes[response.status_code][0],
72113
response.content
73114
))
74-
return (data)
115+
return data
75116

76117
@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+
"""
78153
data = []
79154

80155
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
84159
chunk_seconds = int(end - start)
85160
chunk_size = str(int(chunk_seconds)) + "s"
86161
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())))
88165

89166
if int(end-start) < chunk_seconds:
90167
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
97174
query = metric_name
98175

99176
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)
107184
if response.status_code == 200:
108185
data += response.json()['data']['result']
109186
else:
110-
raise Exception("HTTP Status Code {} {} ({})".format(
187+
raise Exception("HTTP Status Code {} ({})".format(
111188
response.status_code,
112-
requests.status_codes._codes[response.status_code][0],
113189
response.content
114190
))
115191
if store_locally:
116192
# 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)
118196

119197
start += chunk_seconds
120-
return (data)
198+
return data
121199

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):
123201
'''
124-
Function to store metrics locally
202+
Method to store metrics locally
125203
'''
126204
if not values:
127-
return "No values for {}".format(metric_name)
205+
_LOGGER.debug("No values for %s", metric_name)
206+
return None
128207

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)
131209

132210
if compressed:
133211
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
139217
with open(file_path, "wb") as file:
140218
file.write(payload)
141219

220+
return file_path
221+
142222
def _metric_filename(self, metric_name, end_timestamp):
143223
'''
144224
Adds a timestamp to the filename before it is stored
145225
'''
146226
end_timestamp = dateparser.parse(str(end_timestamp))
147227
directory_name = end_timestamp.strftime("%Y%m%d")
148228
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"
150231
return object_path
151232

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

Comments
 (0)