From 9877bdf22b362c5b6c18a32ee3d1a4d93d6103f0 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Thu, 17 Oct 2019 07:01:00 +0200 Subject: [PATCH] first prometheus impl --- prometheus.py | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100755 prometheus.py diff --git a/prometheus.py b/prometheus.py new file mode 100755 index 0000000..8a053f1 --- /dev/null +++ b/prometheus.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from ejabberdrpc import EjabberdMetrics + +import time +import threading +import socket +from http.server import BaseHTTPRequestHandler, HTTPServer +from socketserver import ThreadingMixIn + +class _ThreadingSimpleServer(ThreadingMixIn, HTTPServer): + """Thread per request HTTP server.""" + # Make worker threads "fire and forget". Beginning with Python 3.7 this + # prevents a memory leak because ``ThreadingMixIn`` starts to gather all + # non-daemon threads in a list in order to join on them at server close. + # Enabling daemon threads virtually makes ``_ThreadingSimpleServer`` the + # same as Python 3.7's ``ThreadingHTTPServer``. + daemon_threads = True + address_family = socket.AF_INET6 + + +class Prometheus(): + def __init__(self, metrics): + self._metrics = metrics + + def _parse_metric(self, name, value, tags=None): + output = name + if isinstance(tags, dict): + output += "{" + first = True + for k, v in tags.items(): + if not first: + output += ', ' + else: + first = False + output += k+'="'+v+'"' + output += '}' + return output + ' {}\n'.format(value) + + def _get_metrics(self): + output = "" + + output += self._parse_metric("ejabberd_registered_total", self._metrics.get_registered()) + + for host in self._metrics.get_vhosts(): + output += self._parse_metric("ejabberd_registered_vhosts", self._metrics.get_registered(host), {"vhost": host}) + + for k, v in self._metrics.get_online_by_node(vhost=host).items(): + output += self._parse_metric("ejabberd_online_vhost_node", v, {"vhost": host, "node": k}) + + for node in self._metrics.get_nodes(): + for k, v in self._metrics.get_online_by_status(node=node, vhost=host).items(): + output += self._parse_metric("ejabberd_online_status", v, {"vhost": host, "node": node, "status": k}) + for k, v in self._metrics.get_online_by_connection(node=node, vhost=host).items(): + output += self._parse_metric("ejabberd_online_connection", v, {"vhost": host, "node": node, "connection": k}) + for k, v in self._metrics.get_online_by_client(node=node, vhost=host).items(): + output += self._parse_metric("ejabberd_online_client", v, {"vhost": host, "node": node, "client": k}) + for k, v in self._metrics.get_online_by_ipversion(node=node, vhost=host).items(): + output += self._parse_metric("ejabberd_online_ipversion", v, {"vhost": host, "node": node, "ipversion": str(k)}) + + # next four lines should be dropped - it should be calc by ejabberd_online_vhost_node + for k, v in self._metrics.get_online_by_node().items(): + output += self._parse_metric("ejabberd_online_node_total", v, {"node": k}) + for k, v in self._metrics.get_online_by_vhost().items(): + output += self._parse_metric("ejabberd_online_vhost_total", v, {"vhost": k}) + + return output + + + def listen(self, port, addr='::'): + """Starts an HTTP server for prometheus metrics as a daemon thread""" + class myHandler(BaseHTTPRequestHandler): + def do_GET(r): + r.send_response(200) + r.send_header('Content-type', 'text/html') + r.end_headers() + result = self._get_metrics() + r.wfile.write(result.encode('utf-8')) + + + httpd = _ThreadingSimpleServer((addr, port), myHandler) + t = threading.Thread(target=httpd.serve_forever) + t.daemon = True + t.start() + +if __name__ == "__main__": + metrics = EjabberdMetrics("http://[::1]:4560") + prom = Prometheus(metrics) + prom.listen(8080) + while True: + metrics.update() + time.sleep(10)