Metrics: collect application metrics via vector #246

Merged
Oleg-Komarov merged 1 commits from metrics into main 2024-09-03 17:01:20 +02:00
2 changed files with 93 additions and 0 deletions

View File

@ -0,0 +1,89 @@
from contextlib import ExitStack
import json
import socket
import time
from django.conf import settings
from django.db import connections
class VectorClient:
def __init__(self):
self._socket = None
self.hostname = socket.gethostname()
@property
def socket(self):
if not self._socket:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return self._socket
def send(self, data):
self.socket.sendto(
bytes(json.dumps(data), "utf-8"),
("127.0.0.1", settings.VECTOR_UDP_PORT),
)
vector_client = VectorClient()
class QueryLogger:
def __init__(self, alias):
self.alias = alias
self.durations = []
def __call__(self, execute, sql, params, many, context):
start = time.perf_counter()
try:
return execute(sql, params, many, context)
finally:
duration = time.perf_counter() - start
self.durations.append(duration)
def metrics_middleware(get_response):
"""All timings reported as integer milliseconds."""
def middleware(request):
# pre-request setup
start = time.perf_counter()
context_managers = []
query_loggers = []
for connection in connections.all():
query_logger = QueryLogger(connection.alias)
query_loggers.append(query_logger)
context_managers.append(connection.execute_wrapper(query_logger))
# request processing
with ExitStack() as stack:
for context_manager in context_managers:
stack.enter_context(context_manager)
response = get_response(request)
# post-request reporting
request_time = int(1000 * (time.perf_counter() - start))
db_metrics = {}
for query_logger in query_loggers:
db_metrics[query_logger.alias] = {
"query_count": len(query_logger.durations),
"query_time_sum": int(1000 * sum(query_logger.durations)),
}
data = {
"db": db_metrics,
"hostname": vector_client.hostname,
"http": {
"path": request.path,
"request_time": request_time,
"remote_addr": request.META.get("REMOTE_ADDR"),
"status_code": response.status_code,
"user_agent": request.headers.get("user-agent"),
},
"service_name": settings.SERVICE_NAME,
}
vector_client.send(data)
return response
return middleware

View File

@ -79,6 +79,7 @@ INSTALLED_APPS = [
]
MIDDLEWARE = [
'blender_extensions.middleware.metrics_middleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@ -354,3 +355,6 @@ if os.environ.get('ADMINS') is not None:
ADMINS = [[_.strip() for _ in adm.split(':')] for adm in os.environ.get('ADMINS').split(',')]
EMAIL_SUBJECT_PREFIX = f'[{ALLOWED_HOSTS[0]}]'
SERVER_EMAIL = f'django@{ALLOWED_HOSTS[0]}'
SERVICE_NAME = os.getenv('SERVICE_NAME', 'dummy_service_name')
VECTOR_UDP_PORT = 18125