Skip to content
Snippets Groups Projects
Commit 210ad382 authored by sguazt's avatar sguazt
Browse files

Prometheus sink: added doc and improved code.

parent ef3b7d75
No related branches found
No related tags found
No related merge requests found
......@@ -16,6 +16,7 @@
## limitations under the License.
##
import base64
from core import measures_sink
import prometheus_client
......@@ -24,11 +25,39 @@ class PrometheusSink(measures_sink.MeasuresSink):
"""Measures sink that pushes metrics to Prometheus
(https://prometheus.io/).
Tested with Prometheus v. 2.22.0 and Prometheys Pushgateway v. 1.3.0.
Tested with Prometheus v. 2.22.0, Prometheus Pushgateway v. 1.3.0 and with
Prometheus client for Python v. 0.8.0.
To setup Prometheus and its Pushgateway:
1. Download the Prometheus binary: https://prometheus.io/download
2. Configure Prometheus by appending the following lines to `prometheus.yml':
- job_name: <JOB>
honor_labels: true
static_configs:
- targets: [<PUSHGATEWAY>]
where <JOB> is the name of the Prometheus job (e.g., 'easycloud'), and
<PUSHGATEWAY> is the host name and port where the pushgateway is
listening to (e.g., 'localhost:9091').
3. Start Prometheus: ./prometheus
4. Download the Prometheus Pushgateway: https://github.com/prometheus/pushgateway/releases
5. Start the Prometheus Pushgateway: ./pushgateway
6. Open in your browser the Prometheus dashboard: https://localhost:9090
7. Open in your browser the Prometheus Pushgateway dashboard: <PUSHGATEWAY> (e.g., https://localhost:9091)
Metrics are organized as follows: we create a different Prometheus collector
registry for each instance, and, for each registry we create a Prometheus
gauge for every metrics we want to monitor.
For instance, if we want to monitor the 'cpu_load' and the 'memory_free'
metrics of two instances, namely 'instance01' and 'instance02', we create 2
registries (one for 'instance01' and another one for 'instance02') and for
each registry we create two gauges (one for the 'cpu_load' metrics and
another one for the 'memory_free' metric).
References:
- Prometheus: https://prometheus.io/
- Prometheus Pushgateway: https://github.com/prometheus/pushgateway
- Prometheus client for Python: https://github.com/prometheus/client_python
- Getting started with Prometheus: https://prometheus.io/docs/prometheus/latest/getting_started/
"""
DEFAULT_PUSHGATEWAY = 'localhost:9091'
......@@ -48,37 +77,58 @@ class PrometheusSink(measures_sink.MeasuresSink):
super(PrometheusSink, self).__init__()
self._pushgateway = pushgateway if (pushgateway is not None) and len(pushgateway) > 0 else self.DEFAULT_PUSHGATEWAY
self._job = job if (job is not None) and len(job) > 0 else self.DEFAULT_JOB
self._registry = prometheus_client.CollectorRegistry()
self._registries = {}
self._gauges = {}
def put(self, measure):
group_id = self._measure_group_encode(self._measure_group(measure))
if group_id not in self._gauges:
self._gagues[group_id] = prometheus_client.Gauge(measure.metrix,
'Metric {} for {}:{}'.format(measure.metric, measure.object_ns, measure.object_id),
registry=self._registry)
self._gauges[group_id].set(measure.value)
metric = measure.metric
##group_id = self._measure_group_encode(self._measure_group(measure)) #XXX: don't use this becasue we need an id that is Base64 compliant
#group_id = base64.urlsafe_b64encode(':'.join(self._measure_group(measure)).encode()).decode()
group_id = self._measure_group_id(measure)
if group_id not in self._registries:
self._registries[group_id] = prometheus_client.CollectorRegistry()
self._gauges[group_id] = {}
if metric not in self._gauges[group_id]:
self._gauges[group_id][metric] = prometheus_client.Gauge(metric,
"Metric '{}' at '{}:{}'".format(metric, measure.object_ns, measure.object_id),
registry=self._registries[group_id])
self._gauges[group_id][metric].set(measure.value)
prometheus_client.push_to_gateway(self._pushgateway,
job=self._job,
grouping_key={'instance@base64': group_id},
registry=self._registry)
registry=self._registries[group_id])
# Use the default implementation
#def mput(self, measures):
# # Groups measures by object namespace, object ID and metric to optimize writes on CSV files
# measures_groups = dict() # {namespace => {object-id => {metric => [measure1, measure2, ...]}}}
# for measure in measures:
# group_id = self._measure_group_encode(self._measure_group(measure))
# if group_id not in measures_groups:
# measures_groups[group_id] = []
# measures_groups[group_id].append(measure)
# if group_id not in self._gauges:
# self._gagues[group_id] = prometheus_client.Gauge(measure.metrix, 'Metric {} for {}:{}'.format(measure.metric, measure.object_ns, measure.object_id), registry=self._registry)
# for group_id in measures_groups:
# msg_key = group_id
# for measure in measures_groups[group_id]:
# self._gauges[group_id].set(measure.value)
# prometheus_client.push_to_gateway(self._pushgateway,
# job=self._job,
# grouping_key={'instance@base64', group_id},
# registry=self._registry)
def mput(self, measures):
# Groups measures by object namespace, object ID and metric to reduce pushing to Prometheus
measures_groups = dict() # {namespace => {object-id => {metric => [measure1, measure2, ...]}}}
for measure in measures:
metric = measure.metric
##group_id = self._measure_group_encode(self._measure_group(measure)) #XXX: don't use this becasue we need an id that is Base64 compliant
#group_id = base64.urlsafe_b64encode(':'.join(self._measure_group(measure)).encode()).decode()
group_id = self._measure_group_id(measure)
if group_id not in measures_groups:
measures_groups[group_id] = []
measures_groups[group_id].append(measure)
print("METRIC {}".format(metric))
print("--> Registries: {}".format(self._registries))
print("--> Gauges: {}".format(self._gauges))
if group_id not in self._registries:
print("--> Create registry")
self._registries[group_id] = prometheus_client.CollectorRegistry()
self._gauges[group_id] = {}
if metric not in self._gauges[group_id]:
print("--> Create gauge")
self._gauges[group_id][metric] = prometheus_client.Gauge(metric,
"Metric '{}' at '{}:{}'".format(metric, measure.object_ns, measure.object_id),
registry=self._registries[group_id])
for group_id in measures_groups:
for measure in measures_groups[group_id]:
self._gauges[group_id][measure.metric].set(measure.value)
prometheus_client.push_to_gateway(self._pushgateway,
job=self._job,
grouping_key={'instance@base64': group_id},
registry=self._registries[group_id])
@classmethod
def _measure_group_id(cls, measure):
return base64.urlsafe_b64encode(':'.join([measure.object_ns, measure.object_id]).encode()).decode()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment