From a83c74e6131ebf8f8558cc3213e0376425a0f85b Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Mon, 13 Aug 2018 12:51:15 +0200 Subject: [PATCH] Support for exporting data to a MQTT server --- conf/glances.conf | 8 +++ docs/gw/index.rst | 1 + docs/gw/mqtt.rst | 23 ++++++++ glances/README.txt | 1 + glances/exports/glances_mqtt.py | 98 +++++++++++++++++++++++++++++++++ optional-requirements.txt | 1 + setup.py | 2 +- 7 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 docs/gw/mqtt.rst create mode 100644 glances/exports/glances_mqtt.py diff --git a/conf/glances.conf b/conf/glances.conf index 65057946..78564ce9 100644 --- a/conf/glances.conf +++ b/conf/glances.conf @@ -399,6 +399,14 @@ user=guest password=guest queue=glances_queue +[mqtt] +# Configuration for the --export mqtt option +host=localhost +port=8883 +user=guest +password=guest +topic=glances + [couchdb] # Configuration for the --export couchdb option # https://www.couchdb.org diff --git a/docs/gw/index.rst b/docs/gw/index.rst index 7f587a4f..82d875f1 100644 --- a/docs/gw/index.rst +++ b/docs/gw/index.rst @@ -18,6 +18,7 @@ to providing stats to multiple services (see list below). influxdb json kafka + mqtt opentsdb prometheus rabbitmq diff --git a/docs/gw/mqtt.rst b/docs/gw/mqtt.rst new file mode 100644 index 00000000..25f2b005 --- /dev/null +++ b/docs/gw/mqtt.rst @@ -0,0 +1,23 @@ +.. _mqtt: + +MQTT +======== + +You can export statistics to an ``MQTT`` server. The +connection should be defined in the Glances configuration file as +following: + +.. code-block:: ini + + [mqtt] + host=localhost + port=883 + user=glances + password=glances + topic=glances + +and run Glances with: + +.. code-block:: console + + $ glances --export mqtt diff --git a/glances/README.txt b/glances/README.txt index bbf94ebf..f7ba0575 100644 --- a/glances/README.txt +++ b/glances/README.txt @@ -44,6 +44,7 @@ exports => Glances export interfaces glances_csv.py The CSV export module glances_influxdb.py The InfluxDB export module + glances_mqtt.py The MQTT export module glances_opentsdb.py The OpenTSDB export module glances_rabbitmq.py The RabbitMQ export module glances_statsd.py The StatsD export module diff --git a/glances/exports/glances_mqtt.py b/glances/exports/glances_mqtt.py new file mode 100644 index 00000000..017e33c8 --- /dev/null +++ b/glances/exports/glances_mqtt.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +# +# This file is part of Glances. +# +# Copyright (C) 2018 Nicolargo +# +# 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 . + +"""MQTT interface class.""" + +import socket +import string + +from glances.logger import logger +from glances.exports.glances_export import GlancesExport + +# Import paho for MQTT +from requests import certs +import paho.mqtt.client as paho + + +class Export(GlancesExport): + + """This class manages the MQTT export module.""" + + def __init__(self, config=None, args=None): + """Init the MQTT export IF.""" + super(Export, self).__init__(config=config, args=args) + + # Mandatories configuration keys (additional to host and port) + self.user = None + self.password = None + self.topic = None + + # Load the MQTT configuration file + self.export_enable = self.load_conf('mqtt', + mandatories=['host', 'password'], + options=['port', 'user', 'topic']) + if not self.export_enable: + exit('Missing MQTT config') + + # Get the current hostname + self.hostname = socket.gethostname() + + self.port = self.port or 8883 + self.topic = self.topic or 'glances' + self.user = self.user or 'glances' + + # Init the MQTT client + self.client = self.init() + + def init(self): + """Init the connection to the MQTT server.""" + if not self.export_enable: + return None + try: + client = paho.Client(client_id='glances_' + self.hostname, + clean_session=False) + client.username_pw_set(username=self.user, + password=self.password) + client.tls_set(certs.where()) + client.connect(host=self.host, + port=self.port) + client.loop_start() + return client + except Exception as e: + logger.critical("Connection to MQTT server failed : %s " % e) + return None + + def export(self, name, columns, points): + """Write the points in MQTT.""" + + WHITELIST='_-' + string.ascii_letters + string.digits + SUBSTITUTE='_' + + def whitelisted(s, + whitelist=WHITELIST, + substitute=SUBSTITUTE): + return ''.join(c if c in whitelist else substitute for c in s) + + for sensor, value in zip(columns, points): + try: + sensor = [whitelisted(name) for name in sensor.split('.')] + topic = '/'.join([self.topic, self.hostname, name, *sensor]) + self.client.publish(topic, value) + except Exception as e: + logger.error("Can not export stats to MQTT server (%s)" % e) diff --git a/optional-requirements.txt b/optional-requirements.txt index a3abd92d..65dc7f14 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -8,6 +8,7 @@ influxdb kafka-python netifaces nvidia-ml-py3 +paho-mqtt pika potsdb prometheus_client diff --git a/setup.py b/setup.py index c72a0ec8..d66fd93d 100755 --- a/setup.py +++ b/setup.py @@ -89,7 +89,7 @@ setup( 'cpuinfo': ['py-cpuinfo'], 'docker': ['docker>=2.0.0'], 'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch', - 'influxdb>=1.0.0', 'kafka-python', 'pika', 'potsdb', + 'influxdb>=1.0.0', 'kafka-python', 'pika', 'paho-mqtt', 'potsdb', 'prometheus_client', 'pyzmq', 'statsd'], 'folders': ['scandir'], # python_version<"3.5" 'gpu': ['nvidia-ml-py3'], # python_version=="2.7"