Skip to content

Commit

Permalink
feat: add initial prometheus metrics support
Browse files Browse the repository at this point in the history
Prometheus environments want metrics to be in specific formats. So the
metrics are slightly different from the monitoring endpoint.

Some metrics were not transfered over from the monitoring endpoint because in
a Prometheus environment one is likely to have other methods
(node_exporter, blackbox_exporter) to monitor some aspects.
  • Loading branch information
ykuksenko committed Mar 29, 2023
1 parent b28316a commit f7f8068
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
21 changes: 21 additions & 0 deletions api/tacticalrmm/core/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,24 @@ def wrap(request, *args, **kwargs):
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap

def metrics_view(function):
def wrap(request, *args, **kwargs):
if request.method != "GET":
return HttpResponse("Invalid request type\n", status=400)

if "Authorization" not in request.headers:
return HttpResponse("Missing 'Authorization' header\n", status=400)

token = getattr(settings, "MON_TOKEN", "")
if not token:
return HttpResponse("Missing token config\n", status=401)

if request.headers["Authorization"] != 'Bearer ' + token:
return HttpResponse("Not authenticated\n", status=401)

return function(request, *args, **kwargs)

wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap
46 changes: 44 additions & 2 deletions api/tacticalrmm/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytz
from cryptography import x509
from django.conf import settings
from django.http import JsonResponse
from django.http import JsonResponse, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import timezone as djangotime
from django.views.decorators.csrf import csrf_exempt
Expand All @@ -15,7 +15,7 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from core.decorators import monitoring_view
from core.decorators import monitoring_view, metrics_view
from core.utils import get_core_settings, sysd_svc_is_running, token_is_valid
from logs.models import AuditLog
from tacticalrmm.constants import AuditActionType, PAStatus
Expand Down Expand Up @@ -449,3 +449,45 @@ def status(request):
"nginx": sysd_svc_is_running("nginx.service"),
}
return JsonResponse(ret, json_dumps_params={"indent": 2})

@csrf_exempt
@metrics_view
def metrics(request):
from agents.models import Agent
from clients.models import Client, Site
cert_file, _ = get_certs()
cert_bytes = Path(cert_file).read_bytes()
cert = x509.load_pem_x509_certificate(cert_bytes)
cert_expiration = cert.not_valid_after.timestamp()
metrics = [
'trmm_buildinfo{{version="{}"}} 1'.format(settings.TRMM_VERSION),
'trmm_meshinfo{{version="{}"}} 1'.format(settings.MESH_VER),
'trmm_natsinfo{{version="{}"}} 1'.format(settings.NATS_SERVER_VER),
'trmm_appinfo{{version="{}"}} 1'.format(settings.APP_VER),
'trmm_agent{{latest_version="{}"}} 1'.format(settings.LATEST_AGENT_VER),
"trmm_agent_count {}".format(Agent.objects.count()),
"trmm_client_count {}".format(Client.objects.count()),
"trmm_site_count {}".format(Site.objects.count()),
"trmm_cert_expiration_time {}".format(cert_expiration),
]

if settings.DOCKER_BUILD:
metrics.append("trmm_docker_build 1")
else:
metrics.append("trmm_docker_build 0")
services = {
"django": "rmm.service",
"mesh": "meshcentral.service",
"daphne": "daphne.service",
"celery": "celery.service",
"celerybeat": "celerybeat.service",
"redis": "redis-server.service",
"postgres": "postgresql.service",
"mongo": "mongod.service",
"nats": "nats.service",
"nats-api": "nats-api.service",
"nginx": "nginx.service",
}
for k,v in services.items():
metrics.append('trmm_service{{name="{}",unit="{}"}} {}'.format(k,v,int(sysd_svc_is_running(v))))
return HttpResponse(("\n").join(metrics),content_type="text/plain")
2 changes: 2 additions & 0 deletions api/tacticalrmm/tacticalrmm/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from accounts.views import CheckCreds, LoginView
from agents.consumers import SendCMD
from core.consumers import DashInfo
from core import views as core_views


class AgentIDConverter:
Expand Down Expand Up @@ -32,6 +33,7 @@ def to_url(self, value):
path("winupdate/", include("winupdate.urls")),
path("software/", include("software.urls")),
path("core/", include("core.urls")),
path("metrics", core_views.metrics),
path("automation/", include("automation.urls")),
path("tasks/", include("autotasks.urls")),
path("logs/", include("logs.urls")),
Expand Down

0 comments on commit f7f8068

Please sign in to comment.