Skip to content

Commit 235bca5

Browse files
committed
raw counters for prometheus api
Signed-off-by: hwassman <[email protected]>
1 parent 8002bc2 commit 235bca5

File tree

6 files changed

+61
-16
lines changed

6 files changed

+61
-16
lines changed

.pydevproject

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
22
<?eclipse-pydev version="1.0"?><pydev_project>
3-
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
4-
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
3+
4+
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
5+
6+
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
7+
8+
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
9+
<path>/${PROJECT_DIR_NAME}</path>
10+
</pydev_pathproperty>
511
</pydev_project>

source/collector.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ def parse_tags(self, filtersMap):
8686
else:
8787
self.tags[_key] = _values.pop()
8888

89+
def reduce_dps_to_first_not_none(self, reverse_order=False):
90+
"""Reduce multiple data points(dps) of a single
91+
TimeSeries to the first non null value in a sorted order.
92+
Optionally the order of timestamps can be reversed.
93+
"""
94+
if len(self.dps) > 1:
95+
logger = getBridgeLogger()
96+
timestamps = sorted(self.dps.keys(), reverse=reverse_order)
97+
self.dps = next((
98+
{timestmp: self.dps[timestmp]} for timestmp in timestamps if
99+
self.dps[timestmp] is not None), {})
100+
if len(self.dps) == 0:
101+
logger.warning(f'Received null values in all data points for {self.metricname}')
102+
89103

90104
class MetricTimeSeries(object):
91105

@@ -154,9 +168,17 @@ def _setup_static_metrics_data(self, metric_names: List[str]):
154168
mDict = {}
155169
md = MetadataHandler()
156170
spec = md.metricsDesc
157-
type = 'histogram' if self.sensor == 'GPFSWaiters' else 'gauge'
171+
metricsTypes = md.metaData.metricsType
172+
173+
mtype = 'gauge'
158174
for name in metric_names:
159-
ts = MetricTimeSeries(name, spec.get(name, "Desc not found"), type)
175+
if self.sensor == 'GPFSWaiters':
176+
mtype = 'histogram'
177+
elif metricsTypes.get(name, None) == "counter":
178+
mtype = 'counter'
179+
ts = MetricTimeSeries(name,
180+
spec.get(name, "Desc not found"),
181+
mtype)
160182
mDict[name] = ts
161183
self.metrics = mDict
162184

@@ -310,6 +332,9 @@ def _collect(self):
310332

311333
res = self.md.qh.runQuery(self.query)
312334
if res is None:
335+
self.logger.error(MSG['NoData'])
336+
# self.stop_collect()
337+
# raise cherrypy.HTTPError(400, MSG['NoData'])
313338
return
314339
self.logger.details("res.rows length: {}".format(len(res.rows)))
315340
if self.removeNoData:

source/config.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ protocol = http
1414
##################### Prometheus Exporter API Connection Defaults #############
1515
# Port number the bridge listening on for Prometheus server https requests;
1616
# ssl cert and key configuration required
17-
1817
# prometheus = 9250
1918

19+
# Sensor counters deltas will be exported by default.
20+
# Set True if you want export original sensor counters.
21+
# rawCounters = False
22+
23+
2024
#################################### API SSL OAuth ############################
2125
[tls]
2226
# Directory path of tls key and cert file location

source/prometheus.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@
3232
class PrometheusExporter(object):
3333
exposed = True
3434

35-
def __init__(self, logger, mdHandler, port):
35+
def __init__(self, logger, mdHandler, port, raw_data=False):
3636
self.logger = logger
3737
self.__md = mdHandler
3838
self.port = port
39+
self.raw_data = raw_data
3940
self.static_sensors_list = ['CPU', 'Memory', 'GPFSFileset']
4041
self.cache_strategy = False
4142
self.caching_collectors = []
@@ -60,6 +61,8 @@ def format_response(self, data) -> [str]:
6061
header = metric.str_descfmt()
6162
resp.extend(header)
6263
for sts in metric.timeseries:
64+
if self.raw_data:
65+
sts.reduce_dps_to_first_not_none(reverse_order=True)
6366
for _key, _value in sts.dps.items():
6467
sts_resp = SingleTimeSeriesResponse(name, _key, _value, sts.tags, metric.mtype)
6568
self.logger.trace(f'sts_resp.str_expfmt output: {sts_resp.str_expfmt()}')
@@ -121,8 +124,12 @@ def build_collector(self, sensor) -> SensorCollector:
121124

122125
attrs = {}
123126

124-
# if self.cache_strategy:
125-
attrs = {'sensor': sensor, 'period': period, 'nsamples': 1}
127+
if self.raw_data:
128+
attrs = {'sensor': sensor, 'period': period,
129+
'nsamples': period, 'rawData': True}
130+
else:
131+
attrs = {'sensor': sensor, 'period': period,
132+
'nsamples': 1}
126133
request = QueryPolicy(**attrs)
127134
collector = SensorCollector(sensor, period, self.logger, request)
128135

@@ -146,7 +153,7 @@ def GET(self, **params):
146153
resp = self.md.update()
147154

148155
# /metrics_gpfs_disk
149-
elif 'metrics_gpfs_disk' in cherrypy.request.script_name:
156+
elif '/metrics_gpfs_disk' == cherrypy.request.script_name:
150157
resp = self.metrics(['GPFSDisk'])
151158
cherrypy.response.headers['Content-Type'] = 'text/plain'
152159
resString = '\n'.join(resp) + '\n'
@@ -244,21 +251,21 @@ def GET(self, **params):
244251
return resString
245252

246253
# /metrics_gpfs_afm
247-
elif 'metrics_gpfs_afm' in cherrypy.request.script_name:
254+
elif '/metrics_gpfs_afm' == cherrypy.request.script_name:
248255
resp = self.metrics(['GPFSAFM'])
249256
cherrypy.response.headers['Content-Type'] = 'text/plain'
250257
resString = '\n'.join(resp) + '\n'
251258
return resString
252259

253260
# /metrics_gpfs_afmfs
254-
elif 'metrics_gpfs_afmfs' in cherrypy.request.script_name:
261+
elif '/metrics_gpfs_afmfs' == cherrypy.request.script_name:
255262
resp = self.metrics(['GPFSAFMFS'])
256263
cherrypy.response.headers['Content-Type'] = 'text/plain'
257264
resString = '\n'.join(resp) + '\n'
258265
return resString
259266

260267
# /metrics_gpfs_afmfset
261-
elif 'metrics_gpfs_afmfset' in cherrypy.request.script_name:
268+
elif '/metrics_gpfs_afmfset' == cherrypy.request.script_name:
262269
resp = self.metrics(['GPFSAFMFSET'])
263270
cherrypy.response.headers['Content-Type'] = 'text/plain'
264271
resString = '\n'.join(resp) + '\n'
@@ -293,7 +300,7 @@ def GET(self, **params):
293300
return resString
294301

295302
# /metrics_gpfs_diskcap
296-
elif 'metrics_gpfs_diskcap' in cherrypy.request.script_name:
303+
elif '/metrics_gpfs_diskcap' == cherrypy.request.script_name:
297304
resp = self.metrics(['GPFSDiskCap'])
298305
cherrypy.response.headers['Content-Type'] = 'text/plain'
299306
resString = '\n'.join(resp) + '\n'

source/queryHandler/QueryHandler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ def runQuery(self, query):
495495
res = self.__do_RESTCall('perfmon/data', 'GET', params)
496496

497497
if res is None:
498-
self.logger.error('QueryHandler: query response has no data results')
498+
self.logger.debug('QueryHandler: query response has no data results')
499499
return None
500500
try:
501501
result = json.loads(res, strict=False)
@@ -528,7 +528,7 @@ def __do_RESTCall(self, endpoint, requestType='GET', params=None):
528528
raise PerfmonConnError("{} {}".format(_response.status_code, _response.reason))
529529
else:
530530
msg = "Perfmon RESTcall error __ Server responded: {} {}".format(_response.status_code, _response.reason)
531-
self.logger.warning(msg)
531+
self.logger.debug(msg)
532532
if _response.content:
533533
contentMsg = _response.content.decode('utf-8', "strict")
534534
self.logger.details(f'Response content:{contentMsg}')

source/zimonGrafanaIntf.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,10 @@ def main(argv):
261261

262262
if args.get('prometheus', None):
263263
bind_prometheus_server(args)
264-
exporter = PrometheusExporter(logger, mdHandler, args.get('prometheus'))
264+
exporter = PrometheusExporter(logger,
265+
mdHandler,
266+
args.get('prometheus'),
267+
args.get('rawCounters', False))
265268
# query to force update of metadata (zimon feature)
266269
cherrypy.tree.mount(exporter, '/update',
267270
{'/':

0 commit comments

Comments
 (0)