Test Failed
Push — master ( 73a01d...ef36eb )
by Nicolas
04:43
created

glances.exports.glances_prometheus.Export.export()   B

Complexity

Conditions 6

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nop 4
dl 0
loc 34
rs 8.4666
c 0
b 0
f 0
1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
9
"""Prometheus interface class."""
10
11
import sys
12
from numbers import Number
13
14
from prometheus_client import Gauge, start_http_server
15
16
from glances.exports.export import GlancesExport
17
from glances.globals import listkeys
18
from glances.logger import logger
19
20
21
class Export(GlancesExport):
22
    """This class manages the Prometheus export module."""
23
24
    METRIC_SEPARATOR = '_'
25
26
    def __init__(self, config=None, args=None):
27
        """Init the Prometheus export IF."""
28
        super().__init__(config=config, args=args)
29
30
        # Load the Prometheus configuration file section
31
        self.export_enable = self.load_conf('prometheus', mandatories=['host', 'port', 'labels'], options=['prefix'])
32
        if not self.export_enable:
33
            exit('Missing PROMETHEUS config')
34
35
        # Optionals configuration keys
36
        if self.prefix is None:
37
            self.prefix = 'glances'
38
39
        if self.labels is None:
40
            self.labels = 'src:glances'
41
42
        # Init the metric dict
43
        # Perhaps a better method is possible...
44
        self._metric_dict = {}
45
46
        # Keys name (compute in update() method)
47
        self.keys_name = {}
48
49
        # Init the Prometheus Exporter
50
        self.init()
51
52
    def init(self):
53
        """Init the Prometheus Exporter"""
54
        try:
55
            start_http_server(port=int(self.port), addr=self.host)
56
        except Exception as e:
57
            logger.critical(f"Can not start Prometheus exporter on {self.host}:{self.port} ({e})")
58
            sys.exit(2)
59
        else:
60
            logger.info(f"Start Prometheus exporter on {self.host}:{self.port}")
61
62
    def update(self, stats):
63
        self.keys_name = {k: stats.get_plugin(k).get_key() for k in stats.getPluginsList()}
64
        super().update(stats)
65
66
    def export(self, name, columns, points):
67
        """Write the points to the Prometheus exporter using Gauge."""
68
        logger.debug(f"Export {name} stats to Prometheus exporter")
69
70
        # Remove non number stats and convert all to float (for Boolean)
71
        data = {str(k): float(v) for k, v in zip(columns, points) if isinstance(v, Number)}
72
73
        # Write metrics to the Prometheus exporter
74
        for metric, value in data.items():
75
            labels = self.labels
76
            metric_name = self.prefix + self.METRIC_SEPARATOR + name + self.METRIC_SEPARATOR
77
            try:
78
                obj, stat = metric.split('.')
79
                metric_name += stat
80
                labels += f",{self.keys_name.get(name)}:{obj}"
81
            except ValueError:
82
                metric_name += metric
83
84
            # Prometheus is very sensible to the metric name
85
            # See: https://prometheus.io/docs/practices/naming/
86
            for c in ' .-/:[]':
87
                metric_name = metric_name.replace(c, self.METRIC_SEPARATOR)
88
89
            # Get the labels
90
            labels = self.parse_tags(labels)
91
            # Manage an internal dict between metric name and Gauge
92
            if metric_name not in self._metric_dict:
93
                self._metric_dict[metric_name] = Gauge(metric_name, "", labelnames=listkeys(labels))
94
            # Write the value
95
            if hasattr(self._metric_dict[metric_name], 'labels'):
96
                # Add the labels (see issue #1255)
97
                self._metric_dict[metric_name].labels(**labels).set(value)
98
            else:
99
                self._metric_dict[metric_name].set(value)
100