Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
EasyCloud
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
DSDF
EasyCloud
Commits
210ad382
Commit
210ad382
authored
4 years ago
by
sguazt
Browse files
Options
Downloads
Patches
Plain Diff
Prometheus sink: added doc and improved code.
parent
ef3b7d75
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
core/measures_sink/prometheus.py
+78
-28
78 additions, 28 deletions
core/measures_sink/prometheus.py
with
78 additions
and
28 deletions
core/measures_sink/prometheus.py
+
78
−
28
View file @
210ad382
...
...
@@ -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
.
_registr
y
=
prometheus_client
.
CollectorRegistry
()
self
.
_registr
ies
=
{}
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
.
_registr
y
)
registry
=
self
.
_registr
ies
[
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
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment