From 5cb6f874452d559008f6387caf670cf7cc21b7fc Mon Sep 17 00:00:00 2001 From: Jenny Danzmayr Date: Fri, 29 Mar 2024 23:38:04 +0100 Subject: [PATCH] added prometheus metrics exporter --- docker/Dockerfile | 1 + src/c3nav/mapdata/apps.py | 1 + src/c3nav/mapdata/metrics.py | 30 ++++++++++++++++++++++++++++++ src/c3nav/settings.py | 14 +++++++++++++- src/c3nav/urls.py | 5 +++++ src/requirements/metrics.txt | 1 + 6 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/c3nav/mapdata/metrics.py create mode 100644 src/requirements/metrics.txt diff --git a/docker/Dockerfile b/docker/Dockerfile index 4d5bcc3d..d79285d0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -67,6 +67,7 @@ RUN --mount=type=cache,target=/pip-cache \ -r requirements/memcached.txt \ -r requirements/rsvg.txt \ -r requirements/sentry.txt \ + -r requirements/metrics.txt \ -r requirements/server-asgi.txt && \ pip install --cache-dir /pip-cache uwsgi diff --git a/src/c3nav/mapdata/apps.py b/src/c3nav/mapdata/apps.py index c2f18bc0..5d47afa1 100644 --- a/src/c3nav/mapdata/apps.py +++ b/src/c3nav/mapdata/apps.py @@ -7,3 +7,4 @@ class MapdataConfig(AppConfig): def ready(self): from c3nav.mapdata.utils.cache.changes import register_signals register_signals() + import c3nav.mapdata.metrics # noqa diff --git a/src/c3nav/mapdata/metrics.py b/src/c3nav/mapdata/metrics.py new file mode 100644 index 00000000..a8501a7f --- /dev/null +++ b/src/c3nav/mapdata/metrics.py @@ -0,0 +1,30 @@ +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.cache import cache + +from c3nav.mapdata.models.report import Report + +if settings.METRCIS: + from prometheus_client import Gauge + from prometheus_client.core import REGISTRY, CounterMetricFamily + from prometheus_client.registry import Collector + + users_total = Gauge('c3nav_users_total', 'Total number of users') + users_total.set_function(lambda: get_user_model().objects.count()) + reports_total = Gauge('c3nav_reports_total', 'Total number of reports') + reports_total.set_function(lambda: Report.objects.count()) + reports_open = Gauge('c3nav_reports_open', 'Number of open reports') + reports_open.set_function(lambda: Report.objects.filter(open=True).count()), + + class APIStatsCollector(Collector): + def collect(self): + if settings.CACHES['default']['BACKEND'] == 'django.core.cache.backends.redis.RedisCache': + client = cache._cache.get_client() + for key in client.keys(f"*{settings.CACHES['default'].get('KEY_PREFIX', '')}apistats__*"): + key = key.decode('utf-8').split(':', 2)[2] + yield CounterMetricFamily(f'c3nav_{key}', key, value=cache.get(key)) + + def describe(self): + return list() + + REGISTRY.register(APIStatsCollector()) diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index 3542dda0..193421af 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -7,7 +7,6 @@ from contextlib import suppress from pathlib import Path from typing import Optional -import sass from django.contrib.messages import constants as messages from django.core.exceptions import ImproperlyConfigured from django.utils.crypto import get_random_string @@ -394,6 +393,19 @@ with suppress(ImportError): import django_extensions # noqa INSTALLED_APPS.append('django_extensions') +METRCIS = config.getboolean('c3nav', 'metrics', fallback=False) +if METRCIS: + try: + import django_prometheus # noqa + INSTALLED_APPS.append('django_prometheus') + MIDDLEWARE = [ + 'django_prometheus.middleware.PrometheusBeforeMiddleware', + *MIDDLEWARE, + 'django_prometheus.middleware.PrometheusAfterMiddleware', + ] + except ImportError: + METRCIS = False + # Security settings X_FRAME_OPTIONS = 'DENY' diff --git a/src/c3nav/urls.py b/src/c3nav/urls.py index 0060ea8d..fa2288e7 100644 --- a/src/c3nav/urls.py +++ b/src/c3nav/urls.py @@ -47,3 +47,8 @@ if settings.SERVE_ANYTHING: with suppress(ImportError): import debug_toolbar urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls))) + + if settings.METRCIS: + with suppress(ImportError): + import django_prometheus # noqu + urlpatterns.insert(0, path('prometheus/', include('django_prometheus.urls'))) diff --git a/src/requirements/metrics.txt b/src/requirements/metrics.txt new file mode 100644 index 00000000..37036346 --- /dev/null +++ b/src/requirements/metrics.txt @@ -0,0 +1 @@ +django_prometheus==2.3.1 \ No newline at end of file