ejabberd-tools/prometheus.py

152 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
from http.server import BaseHTTPRequestHandler, HTTPServer, ThreadingHTTPServer
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 Exception as exception:
self.send_error(500, f"error generating metric output: {exception}")
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()
)
nodename = self._metrics.nodename
Gauge("ejabberd_node_uptime", "uptime of ejabberd service", ["node"], registry=registry).labels(nodename).set(
self._metrics.get_uptime()
)
Gauge("ejabberd_node_proccess", "count of pejabber proccess", ["node"], registry=registry).labels(nodename).set(
self._metrics.get_processes()
)
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 = ThreadingHTTPServer(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))