summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicolargo <nicolas@nicolargo.com>2021-05-12 07:24:38 +0200
committernicolargo <nicolas@nicolargo.com>2021-05-12 07:24:38 +0200
commite8e03437593e1beb95addd80dabf88e9e2c026eb (patch)
treeeeffc397da52a20535d5b136e467f290034fcec4
parent0448e3432f5d48185d4c9e2ecff8b801fcfabb9e (diff)
parentdeccc887c0035b5c8ada23db93c527c7d6f7fdfe (diff)
Merge branch 'issue1854' into develop
-rw-r--r--README.rst3
-rw-r--r--conf/glances.conf11
-rw-r--r--docs/gw/graphite.rst34
-rw-r--r--glances/exports/glances_graphite.py126
-rw-r--r--glances/exports/glances_opentsdb.py2
-rw-r--r--glances/exports/glances_statsd.py2
-rw-r--r--optional-requirements.txt1
-rwxr-xr-xsetup.py6
8 files changed, 179 insertions, 6 deletions
diff --git a/README.rst b/README.rst
index e518768e..e7c9cb43 100644
--- a/README.rst
+++ b/README.rst
@@ -75,6 +75,7 @@ Optional dependencies:
- ``couchdb`` (for the CouchDB export module)
- ``docker`` (for the Docker monitoring support) [Linux/macOS-only]
- ``elasticsearch`` (for the Elastic Search export module)
+- ``graphitesender`` (For the Graphite export module)
- ``hddtemp`` (for HDD temperature monitoring support) [Linux-only]
- ``influxdb`` (for the InfluxDB version 1 export module)
- ``influxdb-client`` (for the InfluxDB version 2 export module) [Only for Python >= 3.6]
@@ -409,7 +410,7 @@ Gateway to other services
Glances can export stats to: ``CSV`` file, ``JSON`` file, ``InfluxDB``, ``Cassandra``, ``CouchDB``,
``OpenTSDB``, ``Prometheus``, ``StatsD``, ``ElasticSearch``, ``RabbitMQ/ActiveMQ``,
-``ZeroMQ``, ``Kafka``, ``Riemann`` and ``RESTful`` server.
+``ZeroMQ``, ``Kafka``, ``Riemann``, ``Graphite`` and ``RESTful`` server.
How to contribute ?
===================
diff --git a/conf/glances.conf b/conf/glances.conf
index 0ed47419..3a0b8755 100644
--- a/conf/glances.conf
+++ b/conf/glances.conf
@@ -586,6 +586,17 @@ port=6789
protocol=http
path=/
+[graphite]
+# Configuration for the --export graphite option
+# https://graphiteapp.org/
+host=localhost
+port=2003
+# Prefix will be added for all measurement name
+prefix=glances
+# System name added between the prefix and the stats
+# By default, system_name = FQDN
+#system_name=mycomputer
+
##############################################################################
# AMPS
# * enable: Enable (true) or disable (false) the AMP
diff --git a/docs/gw/graphite.rst b/docs/gw/graphite.rst
new file mode 100644
index 00000000..a2939802
--- /dev/null
+++ b/docs/gw/graphite.rst
@@ -0,0 +1,34 @@
+.. _graphite:
+
+Graphite
+========
+
+You can export statistics to a ``Graphite`` server (time series server).
+
+The connection should be defined in the Glances configuration file as
+following:
+
+.. code-block:: ini
+
+ [graphite]
+ host=localhost
+ port=2003
+ # Prefix will be added for all measurement name
+ # Ex: prefix=foo
+ # => foo.cpu
+ # => foo.mem
+ # You can also use dynamic values
+ #prefix=`hostname`
+ prefix=glances
+
+and run Glances with:
+
+.. code-block:: console
+
+ $ glances --export graphite
+
+Note 1: the port defines the TCP port where the Graphite listen plain-text requests.
+
+Note 2: As many time-series database, only integer and float are supported in the Graphite datamodel.
+
+Note 3: Under the wood, Glances uses GraphiteSender Python lib (https://github.com/NicoAdrian/graphitesender).
diff --git a/glances/exports/glances_graphite.py b/glances/exports/glances_graphite.py
new file mode 100644
index 00000000..a5c96b0b
--- /dev/null
+++ b/glances/exports/glances_graphite.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Glances.
+#
+# Copyright (C) 2021 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/>.
+
+"""Graphite interface class."""
+
+import sys
+from numbers import Number
+
+from glances.compat import range
+from glances.logger import logger
+from glances.exports.glances_export import GlancesExport
+
+from graphitesend import GraphiteClient
+
+
+class Export(GlancesExport):
+
+ """This class manages the Graphite export module."""
+
+ def __init__(self, config=None, args=None):
+ """Init the Graphite export IF."""
+ super(Export, self).__init__(config=config, args=args)
+
+ # Mandatories configuration keys (additional to host and port)
+ # N/A
+
+ # Optionals configuration keys
+ self.debug = False
+ self.prefix = None
+ self.system_name = None
+
+ # Load the configuration file
+ self.export_enable = self.load_conf('graphite',
+ mandatories=['host',
+ 'port'],
+ options=['prefix',
+ 'system_name'])
+ if not self.export_enable:
+ sys.exit(2)
+
+ # Default prefix for stats is 'glances'
+ if self.prefix is None:
+ self.prefix = 'glances'
+
+ # Convert config option type
+ self.port = int(self.port)
+
+ # Init the Graphite client
+ self.client = self.init()
+
+ def init(self):
+ """Init the connection to the Graphite server."""
+ client = None
+
+ if not self.export_enable:
+ return client
+
+ try:
+ if self.system_name is None:
+ client = GraphiteClient(graphite_server=self.host,
+ graphite_port=self.port,
+ prefix=self.prefix,
+ lowercase_metric_names=True,
+ debug=self.debug)
+ else:
+ client = GraphiteClient(graphite_server=self.host,
+ graphite_port=self.port,
+ prefix=self.prefix,
+ system_name=self.system_name,
+ lowercase_metric_names=True,
+ debug=self.debug)
+ except Exception as e:
+ logger.error("Can not write data to Graphite server: {}:{} ({})".format(self.host,
+ self.port,
+ e))
+ client = None
+ else:
+ logger.info(
+ "Stats will be exported to Graphite server: {}:{}".format(self.host,
+ self.port))
+
+ return client
+
+ def export(self, name, columns, points):
+ """Export the stats to the Graphite server."""
+ if self.client is None:
+ return False
+ before_filtering_dict = dict(zip(
+ [normalize('{}.{}'.format(name, i)) for i in columns],
+ points))
+ after_filtering_dict = dict(
+ filter(lambda i: isinstance(i[1], Number),
+ before_filtering_dict.items()))
+ try:
+ self.client.send_dict(after_filtering_dict)
+ except Exception as e:
+ logger.error("Can not export stats to Graphite (%s)" % e)
+ return False
+ else:
+ logger.debug("Export {} stats to Graphite".format(name))
+ return True
+
+
+def normalize(name):
+ """Normalize name for the Graphite convention"""
+
+ # Name should not contain space
+ ret = name.replace(' ', '_')
+
+ return ret
diff --git a/glances/exports/glances_opentsdb.py b/glances/exports/glances_opentsdb.py
index 5d2b6f5c..4cd2d4fd 100644
--- a/glances/exports/glances_opentsdb.py
+++ b/glances/exports/glances_opentsdb.py
@@ -44,7 +44,7 @@ class Export(GlancesExport):
self.prefix = None
self.tags = None
- # Load the InfluxDB configuration file
+ # Load the configuration file
self.export_enable = self.load_conf('opentsdb',
mandatories=['host', 'port'],
options=['prefix', 'tags'])
diff --git a/glances/exports/glances_statsd.py b/glances/exports/glances_statsd.py
index 0bae6a53..8ccfe7d9 100644
--- a/glances/exports/glances_statsd.py
+++ b/glances/exports/glances_statsd.py
@@ -43,7 +43,7 @@ class Export(GlancesExport):
# Optionals configuration keys
self.prefix = None
- # Load the InfluxDB configuration file
+ # Load the configuration file
self.export_enable = self.load_conf('statsd',
mandatories=['host', 'port'],
options=['prefix'])
diff --git a/optional-requirements.txt b/optional-requirements.txt
index fe7d440d..2ce26877 100644
--- a/optional-requirements.txt
+++ b/optional-requirements.txt
@@ -8,6 +8,7 @@ chevron
couchdb
docker>=2.0.0
elasticsearch
+graphitesender
hddtemp
influxdb
influxdb-client; python_version >= "3.6"
diff --git a/setup.py b/setup.py
index f64e31d2..4ddff21a 100755
--- a/setup.py
+++ b/setup.py
@@ -52,14 +52,14 @@ def get_install_requires():
def get_install_extras_require():
extras_require = {
'action': ['chevron'],
- # Zeroconf 0.19.1 is the latest one compatible with Python 2 (issue #1293)
'browser': ['zeroconf==0.19.1' if PY2 else 'zeroconf>=0.19.1'],
'cloud': ['requests'],
'cpuinfo': ['py-cpuinfo<=4.0.0'],
'docker': ['docker>=2.0.0'],
'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch',
- 'influxdb>=1.0.0', 'kafka-python', 'pika', 'paho-mqtt', 'potsdb',
- 'prometheus_client', 'pyzmq', 'statsd'],
+ 'graphitesender', 'influxdb>=1.0.0', 'kafka-python', 'pika',
+ 'paho-mqtt', 'potsdb', 'prometheus_client', 'pyzmq',
+ 'statsd'],
'folders': ['scandir'], # python_version<"3.5"
'gpu': ['py3nvml'],
'graph': ['pygal'],