diff --git a/README.rst b/README.rst index 9caa49c4..e7c9cb43 100644 --- a/README.rst +++ b/README.rst @@ -75,7 +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) -- ``graphyte`` (For the Graphite 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] diff --git a/conf/glances.conf b/conf/glances.conf index f1bd101d..3a0b8755 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -591,15 +591,11 @@ path=/ # https://graphiteapp.org/ host=localhost port=2003 -protocol=tcp -batch_size=1000 # 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 +# System name added between the prefix and the stats +# By default, system_name = FQDN +#system_name=mycomputer ############################################################################## # AMPS diff --git a/docs/gw/graphite.rst b/docs/gw/graphite.rst index 87889bb5..a2939802 100644 --- a/docs/gw/graphite.rst +++ b/docs/gw/graphite.rst @@ -13,8 +13,6 @@ following: [graphite] host=localhost port=2003 - protocol=udp - batch_size=1000 # Prefix will be added for all measurement name # Ex: prefix=foo # => foo.cpu @@ -29,9 +27,8 @@ and run Glances with: $ glances --export graphite -Note 1: the port defines the TCP or UDP port where the Graphite listen plain-text requests +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 Graphyte Python lib (https://pypi.org/project/graphyte/) - \ No newline at end of file +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 index ba25a08a..a5c96b0b 100644 --- a/glances/exports/glances_graphite.py +++ b/glances/exports/glances_graphite.py @@ -26,7 +26,7 @@ from glances.compat import range from glances.logger import logger from glances.exports.glances_export import GlancesExport -import graphyte +from graphitesend import GraphiteClient class Export(GlancesExport): @@ -41,17 +41,16 @@ class Export(GlancesExport): # N/A # Optionals configuration keys + self.debug = False self.prefix = None - self.protocol = None - self.batch_size = None + self.system_name = None # Load the configuration file self.export_enable = self.load_conf('graphite', - mandatories=['host', + mandatories=['host', 'port'], options=['prefix', - 'protocol', - 'batch_size']) + 'system_name']) if not self.export_enable: sys.exit(2) @@ -59,72 +58,63 @@ class Export(GlancesExport): if self.prefix is None: self.prefix = 'glances' - if self.protocol is None: - self.protocol = 'tcp' - - if self.batch_size is None: - self.batch_size = 1000 - # Convert config option type self.port = int(self.port) - self.batch_size = int(self.batch_size) # 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 None + return client - client = graphyte.Sender(self.host, - port=self.port, - prefix=self.prefix, - protocol=self.protocol, - batch_size=self.batch_size) - - # !!! Except is never reached... - # !!! Have to find away to test the connection with the Graphite server - # !!! Waiting that, have to set the logger to debug in the export function - # try: - # client.send("check", 1) - # except Exception as e: - # logger.error("Can not write data to Graphite server: {}:{}/{} ({})".format(self.host, - # self.port, - # self.protocol, - # e)) - # return None - # else: - # logger.info( - # "Stats will be exported to Graphite server: {}:{}/{}".format(self.host, - # self.port, - # self.protocol)) - - # return client - - logger.info( - "Stats will be exported to Graphite server: {}:{}/{}".format(self.host, - self.port, - self.protocol)) + 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.""" - for i in range(len(columns)): - if not isinstance(points[i], Number): - # Only Int and Float are supported in the Graphite datamodel - continue - stat_name = '{}.{}'.format(name, columns[i]) - stat_value = points[i] - try: - self.client.send(normalize(stat_name), - stat_value) - except Exception as e: - # !! Set to error when the connection test is ok - # logger.error("Can not export stats to Graphite (%s)" % e) - logger.debug("Can not export stats to Graphite (%s)" % e) - logger.debug("Export {} stats to Graphite".format(name)) + 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): diff --git a/optional-requirements.txt b/optional-requirements.txt index 2a49ef2a..2ce26877 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -8,7 +8,7 @@ chevron couchdb docker>=2.0.0 elasticsearch -graphyte +graphitesender hddtemp influxdb influxdb-client; python_version >= "3.6" diff --git a/setup.py b/setup.py index 41feaad2..4ddff21a 100755 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def get_install_extras_require(): 'cpuinfo': ['py-cpuinfo<=4.0.0'], 'docker': ['docker>=2.0.0'], 'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch', - 'graphyte', 'influxdb>=1.0.0', 'kafka-python', 'pika', + 'graphitesender', 'influxdb>=1.0.0', 'kafka-python', 'pika', 'paho-mqtt', 'potsdb', 'prometheus_client', 'pyzmq', 'statsd'], 'folders': ['scandir'], # python_version<"3.5"