diff options
author | nicolargo <nicolas@nicolargo.com> | 2017-03-19 10:42:01 +0100 |
---|---|---|
committer | nicolargo <nicolas@nicolargo.com> | 2017-03-19 10:42:01 +0100 |
commit | 021d4603268e02576a09efc76ad7f7c125b33ab9 (patch) | |
tree | b7d926aef171a76a6ec348f2462b4e453c31b728 | |
parent | c41f74f57970af5718e7e302eeb5df070387a5d7 (diff) |
Implement ok of the Promotheus Exporter, need to add the plugin documentation
-rw-r--r-- | conf/glances.conf | 16 | ||||
-rw-r--r-- | docs/gw/prometheus.rst | 34 | ||||
-rw-r--r-- | glances/exports/glances_cassandra.py | 1 | ||||
-rw-r--r-- | glances/exports/glances_prometheus.py | 89 | ||||
-rw-r--r-- | glances/main.py | 18 | ||||
-rw-r--r-- | optional-requirements.txt | 1 | ||||
-rwxr-xr-x | setup.py | 3 |
7 files changed, 153 insertions, 9 deletions
diff --git a/conf/glances.conf b/conf/glances.conf index 125115a3..e81b34fa 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -361,6 +361,22 @@ port=5678 # - Third frame with the Glances plugin stats (JSON) prefix=G +[prometheus] +# Configuration for the --export-prometheus option +# https://prometheus.io +# Create a Prometheus exporter listening on localhost:9091 (default configuration) +# Metric are exporter using the following name: +# <prefix>_<plugin>_<stats> (all specials character are replaced by '_') +# Note: You should add this exporter to your Prometheus server configuration: +# scrape_configs: +# - job_name: 'glances_exporter' +# scrape_interval: 5s +# static_configs: +# - targets: ['localhost:9091'] +host=localhost +port=9091 +prefix=glances + ############################################################################## # AMPS # * enable: Enable (true) or disable (false) the AMP diff --git a/docs/gw/prometheus.rst b/docs/gw/prometheus.rst new file mode 100644 index 00000000..be684e56 --- /dev/null +++ b/docs/gw/prometheus.rst @@ -0,0 +1,34 @@ +.. _cassandra: + +Cassandra +========= + +You can export statistics to a ``Cassandra`` or ``Scylla`` server. +The connection should be defined in the Glances configuration file as +following: + +.. code-block:: ini + + [cassandra] + host=localhost + port=9042 + protocol_version=3 + keyspace=glances + replication_factor=2 + table=localhost + +and run Glances with: + +.. code-block:: console + + $ glances --export-cassandra + +The data model is the following: + +.. code-block:: ini + + CREATE TABLE <table> (plugin text, time timeuuid, stat map<text,float>, PRIMARY KEY (plugin, time)) + +Only numerical stats are stored in the Cassandra table. All the stats +are converted to float. If a stat cannot be converted to float, it is +not stored in the database. diff --git a/glances/exports/glances_cassandra.py b/glances/exports/glances_cassandra.py index 1bc1a1d2..f5a36fb6 100644 --- a/glances/exports/glances_cassandra.py +++ b/glances/exports/glances_cassandra.py @@ -25,6 +25,7 @@ from numbers import Number from glances.logger import logger from glances.exports.glances_export import GlancesExport +from glances.compat import iteritems from cassandra.cluster import Cluster from cassandra.util import uuid_from_time diff --git a/glances/exports/glances_prometheus.py b/glances/exports/glances_prometheus.py new file mode 100644 index 00000000..2f89b476 --- /dev/null +++ b/glances/exports/glances_prometheus.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Glances. +# +# Copyright (C) 2017 Nicolargo <nicolas@nicolargo.com> +# +# Glances is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Glances is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +"""Prometheus interface class.""" + +import sys +from datetime import datetime +from numbers import Number + +from glances.logger import logger +from glances.exports.glances_export import GlancesExport +from glances.compat import iteritems + +from prometheus_client import start_http_server, Gauge + + +class Export(GlancesExport): + + """This class manages the Prometheus export module.""" + + METRIC_SEPARATOR = '_' + + def __init__(self, config=None, args=None): + """Init the Prometheus export IF.""" + super(Export, self).__init__(config=config, args=args) + + # Optionals configuration keys + self.prefix = 'glances' + + # Load the Prometheus configuration file section + self.export_enable = self.load_conf('prometheus', + mandatories=['host', 'port'], + options=['prefix']) + if not self.export_enable: + sys.exit(2) + + # Init the metric dict + # Perhaps a better method is possible... + self._metric_dict = {} + + # Init the Prometheus Exporter + self.init() + + def init(self): + """Init the Prometheus Exporter""" + try: + start_http_server(port=int(self.port), addr=self.host) + except Exception as e: + logger.critical("Can not start Prometheus exporter on {}:{} ({})".format(self.host, self.port, e)) + sys.exit(2) + else: + logger.info("Start Prometheus exporter on {}:{}".format(self.host, self.port)) + + def export(self, name, columns, points): + """Write the points to the Prometheus exporter using Gauge.""" + logger.debug("Export {} stats to Prometheus exporter".format(name)) + + # Remove non number stats and convert all to float (for Boolean) + data = {k: float(v) for (k, v) in iteritems(dict(zip(columns, points))) if isinstance(v, Number)} + + # Write metrics to the Prometheus exporter + for k, v in iteritems(data): + # Prometheus metric name: prefix_<glances stats name> + metric_name = self.prefix + self.METRIC_SEPARATOR + name + self.METRIC_SEPARATOR + k + # Prometheus is very sensible to the metric name + # See: https://prometheus.io/docs/practices/naming/ + for c in ['.', '-', '/', ' ']: + metric_name = metric_name.replace(c, self.METRIC_SEPARATOR) + # Manage an internal dict between metric name and Gauge + if metric_name not in self._metric_dict: + self._metric_dict[metric_name] = Gauge(metric_name, k) + # Write the value + self._metric_dict[metric_name].set(v) diff --git a/glances/main.py b/glances/main.py index 9dfd44a7..2b47e508 100644 --- a/glances/main.py +++ b/glances/main.py @@ -173,22 +173,24 @@ Examples of use: dest='path_graph', help='set the export path for graphs (default is {})'.format(tempfile.gettempdir())) parser.add_argument('--export-csv', default=None, dest='export_csv', help='export stats to a CSV file') - parser.add_argument('--export-influxdb', action='store_true', default=False, - dest='export_influxdb', help='export stats to an InfluxDB server (influxdb lib needed)') parser.add_argument('--export-cassandra', action='store_true', default=False, dest='export_cassandra', help='export stats to a Cassandra or Scylla server (cassandra lib needed)') - parser.add_argument('--export-opentsdb', action='store_true', default=False, - dest='export_opentsdb', help='export stats to an OpenTSDB server (potsdb lib needed)') - parser.add_argument('--export-statsd', action='store_true', default=False, - dest='export_statsd', help='export stats to a StatsD server (statsd lib needed)') + parser.add_argument('--export-couchdb', action='store_true', default=False, + dest='export_couchdb', help='export stats to a CouchDB server (couch lib needed)') parser.add_argument('--export-elasticsearch', action='store_true', default=False, dest='export_elasticsearch', help='export stats to an ElasticSearch server (elasticsearch lib needed)') + parser.add_argument('--export-influxdb', action='store_true', default=False, + dest='export_influxdb', help='export stats to an InfluxDB server (influxdb lib needed)') + parser.add_argument('--export-opentsdb', action='store_true', default=False, + dest='export_opentsdb', help='export stats to an OpenTSDB server (potsdb lib needed)') + parser.add_argument('--export-prometheus', action='store_true', default=False, + dest='export_prometheus', help='export stats to a Prometheus exporter (prometheus_client lib needed)') parser.add_argument('--export-rabbitmq', action='store_true', default=False, dest='export_rabbitmq', help='export stats to rabbitmq broker (pika lib needed)') parser.add_argument('--export-riemann', action='store_true', default=False, dest='export_riemann', help='export stats to riemann broker (bernhard lib needed)') - parser.add_argument('--export-couchdb', action='store_true', default=False, - dest='export_couchdb', help='export stats to a CouchDB server (couch lib needed)') + parser.add_argument('--export-statsd', action='store_true', default=False, + dest='export_statsd', help='export stats to a StatsD server (statsd lib needed)') parser.add_argument('--export-zeromq', action='store_true', default=False, dest='export_zeromq', help='export stats to a ZeroMQ server (pyzmq lib needed)') # Client/Server option diff --git a/optional-requirements.txt b/optional-requirements.txt index 61527d31..5ae9990b 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -10,6 +10,7 @@ netifaces nvidia-ml-py; python_version == "2.7" pika potsdb +prometheus_client py-cpuinfo pymdstat pysnmp @@ -85,7 +85,8 @@ setup( 'chart': ['matplotlib'], 'docker': ['docker>=2.0.0'], 'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch', - 'influxdb>=1.0.0', 'pika', 'potsdb', 'pyzmq', 'statsd'], + 'influxdb>=1.0.0', 'pika', 'potsdb', 'prometheus_client', + 'pyzmq', 'statsd'], 'folders:python_version<"3.5"': ['scandir'], 'gpu:python_version=="2.7"': ['nvidia-ml-py'], 'ip': ['netifaces'], |