aboutsummaryrefslogtreecommitdiffstats
path: root/prometheus.py
blob: da0d24c0c62d8ec7fa3b0b9e720e01eb393a0d31 (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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import logging
from http.server import BaseHTTPRequestHandler, HTTPServer
from socket import AF_INET6
from time import time
from urllib.parse import parse_qs, urlparse

from prometheus_client import (
    CollectorRegistry, Gauge, generate_latest, CONTENT_TYPE_LATEST
)

from config import Config
from metrics import EjabberdMetrics


class DynamicMetricsHandler(BaseHTTPRequestHandler):
    """HTTP handler that gives metrics from ``core.REGISTRY``."""
    def do_GET(self):
        params = parse_qs(urlparse(self.path).query)
        registry = self.generator(params)
        if 'name[]' in params:
            registry = registry.restricted_registry(params['name[]'])
        try:
            output = generate_latest(registry)
        except:
            self.send_error(500, 'error generating metric output')
            raise
        self.send_response(200)
        self.send_header('Content-Type', CONTENT_TYPE_LATEST)
        self.end_headers()
        self.wfile.write(output)

    @staticmethod
    def factory(registry_generator):
        DynMetricsHandler = type('MetricsHandler',
                                (DynamicMetricsHandler, object),
                                {"generator": registry_generator})
        return DynMetricsHandler


class Prometheus:
    def __init__(self, metrics):
        self.ttl = 10
        self._last_update = 0
        self._metrics = metrics
    
    def handler(self, metrics_handler):
        now = time()
        if now >= (self._last_update + self.ttl):
            self._metrics.update()
            self._last_update = now

        registry = CollectorRegistry(auto_describe=True)

        Gauge('ejabberd_node_s2s_in',  'count of incoming server-to-server connection', registry=registry).set(self._metrics.get_s2s_in())
        Gauge('ejabberd_node_s2s_out', 'count of outgoing server-to-server connection', registry=registry).set(self._metrics.get_s2s_out())

        labelnames_vhost = ["vhost"]

        registered_vhosts = Gauge('ejabberd_registered_vhosts', 'count of user per vhost', labelnames_vhost, registry=registry)
        muc = Gauge('ejabberd_muc', 'count of muc\'s per vhost', labelnames_vhost, registry=registry)

        online_vhost_node = Gauge('ejabberd_online_vhost_node', 'count of client connections', ["vhost", "node"], registry=registry)
        
        online_status = Gauge('ejabberd_online_status', 'count of client connections', ["vhost", "node", "status"], registry=registry)
        online_connection = Gauge('ejabberd_online_connection', 'count of client connections', ["vhost", "node", "connection"], registry=registry)
        online_client = Gauge('ejabberd_online_client', 'count of client software', ["vhost", "node", "client"], registry=registry)
        online_ipversion = Gauge('ejabberd_online_ipversion', 'count of client software', ["vhost", "node", "ipversion"], registry=registry)
        online_client_ipversion = Gauge('ejabberd_online_client_ipversion', 'count of client software', ["vhost", "node", "client", "ipversion"], registry=registry)

        for host in self._metrics.get_vhosts():
            labels_vhost = host

            registered_vhosts.labels(labels_vhost).set(self._metrics.get_registered(host))
            muc.labels(labels_vhost).set(self._metrics.get_muc(host))

            for k, v in self._metrics.get_online_by_node(vhost=host).items():
                online_vhost_node.labels(host, k).set(v)

            for node in self._metrics.get_nodes():
                for k, v in self._metrics.get_online_by_status(node=node, vhost=host).items():
                    online_status.labels(host, node, k).set(v)
                for k, v in self._metrics.get_online_by_connection(node=node, vhost=host).items():
                    online_connection.labels(host, node, k).set(v)
                for k, v in self._metrics.get_online_by_client(node=node, vhost=host).items():
                    online_client.labels(host, node, k).set(v)
                for k, v in self._metrics.get_online_by_ipversion(node=node, vhost=host).items():
                    online_ipversion.labels(host, node, k).set(v)
                for client, data in self._metrics.get_online_client_by_ipversion(node=node, vhost=host).items():
                    for k, v in data.items():
                        online_client_ipversion.labels(host, node, client, str(k)).set(v)

        return registry

    def listen(self, addr=("127.0.0.1", 8080)):
        if "::" in addr[0]:
            HTTPServer.address_family = AF_INET6
        server = HTTPServer(addr, DynamicMetricsHandler.factory(self.handler))
        server.serve_forever()


if __name__ == "__main__":
    # load config
    config = Config()
    if config.get('debug', default=False):
        logging.getLogger().setLevel(logging.DEBUG)

    # 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_addr = config.get('prometheus_address', default='127.0.0.1')
    prom_port = config.get('prometheus_port', default=8080)

    metrics = EjabberdMetrics(url, login, api)
    prom = Prometheus(metrics)
    prom.ttl = config.get('prometheus_cache_ttl', default=10)
    prom.listen((prom_addr, prom_port))