aboutsummaryrefslogtreecommitdiffstats
path: root/prometheus.py
blob: 4441c874f0b15b16a92ab8e9ee72b070d490dd3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import socket
import threading
import time
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn

from config import Config
from metrics import EjabberdMetrics


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_node_s2s_in", self._metrics.get_s2s_in())
        output += self._parse_metric("ejabberd_node_s2s_out", self._metrics.get_s2s_out())
        for host in self._metrics.get_vhosts():
            output += self._parse_metric("ejabberd_registered_vhosts", self._metrics.get_registered(host), {"vhost": host})
            muc = self._metrics.get_muc(host)
            if muc is not None:
                output += self._parse_metric("ejabberd_muc", muc, {"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)})
                for client, data in self._metrics.get_online_client_by_ipversion(node=node,vhost=host).items():
                    for k, v in data.items():
                        output += self._parse_metric("ejabberd_online_client_ipversion", v, {"vhost": host, "node": node, "ipversion": str(k), "client": client})

        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__":
    # load config
    config = Config()

    # credentials and parameters
    url = config.get('url', default='http://[::1]:5280/api')
    login = config.get('login', default=None)
    api = config.get('api', default='rest')

    # config prometheus
    prom_port = config.get('prometheus_port', default=8080)
    prom_refresh = config.get('prometheus_refresh', default=10)

    metrics = EjabberdMetrics(url, login, api)
    prom = Prometheus(metrics)
    prom.listen(prom_port)
    while True:
        metrics.update()
        time.sleep(prom_refresh)