From 0ea21c096028fe2c80b38177d261b528ce3590bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sun, 6 Jun 2021 08:47:47 +0200 Subject: [PATCH] add exporter for uWSGI metrics (#54609) --- debian/prometheus-entrouvert-exporter.install | 1 + ...exporter.prometheus-uwsgi-exporter.service | 6 ++ ...t-exporter.prometheus-uwsgi-exporter.timer | 9 ++ debian/rules | 1 + .../prometheus-uwsgi-exporter.py | 87 +++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.service create mode 100644 debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.timer create mode 100755 prometheus-entrouvert-exporter/prometheus-uwsgi-exporter.py diff --git a/debian/prometheus-entrouvert-exporter.install b/debian/prometheus-entrouvert-exporter.install index 5722229..bfca3d3 100644 --- a/debian/prometheus-entrouvert-exporter.install +++ b/debian/prometheus-entrouvert-exporter.install @@ -1 +1,2 @@ prometheus-entrouvert-exporter/prometheus-system-exporter.py usr/bin +prometheus-entrouvert-exporter/prometheus-uwsgi-exporter.py usr/bin diff --git a/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.service b/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.service new file mode 100644 index 0000000..cd82aec --- /dev/null +++ b/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.service @@ -0,0 +1,6 @@ +[Unit] +Description=Collect uWSGI metrics + +[Service] +Type=oneshot +ExecStart=/usr/bin/prometheus-uwsgi-exporter.py diff --git a/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.timer b/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.timer new file mode 100644 index 0000000..5a479e0 --- /dev/null +++ b/debian/prometheus-entrouvert-exporter.prometheus-uwsgi-exporter.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Run uWSGI metrics collection every minute + +[Timer] +OnBootSec=0 +OnUnitActiveSec=1min + +[Install] +WantedBy=timers.target diff --git a/debian/rules b/debian/rules index 8b0f425..d8f1f4d 100755 --- a/debian/rules +++ b/debian/rules @@ -9,3 +9,4 @@ override_dh_auto_build: override_dh_installsystemd: dh_installsystemd --name=prometheus-system-exporter + dh_installsystemd --name=prometheus-uwsgi-exporter diff --git a/prometheus-entrouvert-exporter/prometheus-uwsgi-exporter.py b/prometheus-entrouvert-exporter/prometheus-uwsgi-exporter.py new file mode 100755 index 0000000..0efe13f --- /dev/null +++ b/prometheus-entrouvert-exporter/prometheus-uwsgi-exporter.py @@ -0,0 +1,87 @@ +#! /usr/bin/python3 + +import collections +import glob +import json +import os +import socket +import statistics + +from prometheus_client import CollectorRegistry, Gauge, write_to_textfile + +registry = CollectorRegistry() + +uwsgi_workers_rss_avg = Gauge( + 'uwsgi_workers_rss_avg', 'Average RSS of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_rss_med = Gauge( + 'uwsgi_workers_rss_med', 'Median RSS of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_rss_max = Gauge( + 'uwsgi_workers_rss_max', 'Maximum RSS of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_vsz_avg = Gauge( + 'uwsgi_workers_vsz_avg', 'Average VSZ of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_vsz_med = Gauge( + 'uwsgi_workers_vsz_med', 'Median VSZ of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_vsz_max = Gauge( + 'uwsgi_workers_vsz_max', 'Maximum VSZ of uwsgi workers', ['app'], registry=registry +) +uwsgi_workers_status = Gauge( + 'uwsgi_workers_status', 'uwsgi workers status', ['app', 'status'], registry=registry +) + + +app_name = None + +for stats_sock in glob.glob('/run/*/stats.sock'): + app_name = stats_sock.split('/')[2] + app_name = app_name.replace('authentic2-multitenant', 'authentic') + stats_json = '' + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: + s.connect(stats_sock) + while True: + data = s.recv(4096) + if not data: + break + stats_json += data.decode('utf8', 'ignore') + stats_data = json.loads(stats_json) + + listen_queue = stats_data['listen_queue'] + workers_rss = [] + workers_vsz = [] + workers_status = collections.defaultdict(int) + workers_status['idle'] = 0 + workers_status['busy'] = 0 + for worker in stats_data['workers']: + if worker['status'] == 'cheap': + continue + workers_status[worker['status']] += 1 + workers_rss.append(worker['rss']) + workers_vsz.append(worker['vsz']) + + uwsgi_workers_rss_max.labels(app=app_name).set(max(workers_rss)) + uwsgi_workers_rss_avg.labels(app=app_name).set(statistics.mean(workers_rss)) + uwsgi_workers_rss_med.labels(app=app_name).set(statistics.median(workers_rss)) + uwsgi_workers_vsz_max.labels(app=app_name).set(max(workers_vsz)) + uwsgi_workers_vsz_avg.labels(app=app_name).set(statistics.mean(workers_vsz)) + uwsgi_workers_vsz_med.labels(app=app_name).set(statistics.median(workers_vsz)) + for k in workers_status: + uwsgi_workers_status.labels(app=app_name, status=k).set(workers_status[k]) + +if app_name: + write_to_textfile('/var/lib/prometheus/node-exporter/uwsgi.prom', registry) +else: + # host for containers? + content = '' + for machine_stat in glob.glob('/var/lib/machines/*/var/lib/prometheus/node-exporter/uwsgi.prom'): + with open(machine_stat) as fd: + content += fd.read() + if content: + with open('/var/lib/prometheus/node-exporter/uwsgi.prom.tmp', 'w') as fd: + fd.write(content) + os.rename( + '/var/lib/prometheus/node-exporter/uwsgi.prom.tmp', '/var/lib/prometheus/node-exporter/uwsgi.prom' + )