Files
pi-qmem/gateway/metrics.py
T
Matteo Benedetto 4776b4b496 refactor: split gateway and pi-qmem extension into modules
- gateway: separate config, models, state, audit, guardrail, embeddings,
  store, metrics, cleanup and routes; keep main.py as FastAPI bootstrap
- extension: split client/config, six tools, config command and rules;
  preserve jiti entrypoint and registrations
- Dockerfile copies the complete gateway module set
- tests: update monkeypatch boundaries for modular config/state
2026-08-24 16:19:19 +02:00

71 lines
2.9 KiB
Python

"""Metriche in-memory e push Prometheus/VictoriaMetrics."""
from __future__ import annotations
import time
from typing import Any
from config import VM_PUSH_INTERVAL, VM_PUSH_URL, _metrics, log
def record_request(endpoint: str, duration: float, status_code: int) -> None:
_metrics["requests"][endpoint] += 1
_metrics["duration_sum"][endpoint] += duration
_metrics["duration_count"][endpoint] += 1
if status_code >= 400:
_metrics["errors"][(endpoint, status_code)] += 1
def record_search(hits: int) -> None:
_metrics["search_queries"] += 1
_metrics["search_hits"] += hits
def snapshot(qdrant: Any, collection: str) -> dict:
try:
points = qdrant.get_collection(collection).points_count
except Exception: # noqa: BLE001
points = None
return {
"requests": dict(_metrics["requests"]),
"avg_duration_ms": {
endpoint: round(_metrics["duration_sum"][endpoint] / _metrics["duration_count"][endpoint] * 1000, 2)
for endpoint in _metrics["duration_count"]
},
"errors": {f"{endpoint}:{status}": count for (endpoint, status), count in _metrics["errors"].items()},
"search_queries": _metrics["search_queries"],
"search_hits": _metrics["search_hits"],
"points": points,
}
def prometheus_lines(qdrant: Any, collection: str) -> list[str]:
lines: list[str] = []
for endpoint, count in _metrics["requests"].items():
lines.append(f'qmem_requests_total{{endpoint="{endpoint}"}} {count}')
for endpoint, total in _metrics["duration_sum"].items():
count = _metrics["duration_count"][endpoint]
lines.append(f'qmem_request_duration_seconds_sum{{endpoint="{endpoint}"}} {total:.6f}')
lines.append(f'qmem_request_duration_seconds_count{{endpoint="{endpoint}"}} {count}')
for (endpoint, status), count in _metrics["errors"].items():
lines.append(f'qmem_errors_total{{endpoint="{endpoint}",status="{status}"}} {count}')
lines.append(f"qmem_search_queries_total {_metrics['search_queries']}")
lines.append(f"qmem_search_hits_total {_metrics['search_hits']}")
try:
lines.append(f"qmem_points {qdrant.get_collection(collection).points_count}")
except Exception: # noqa: BLE001
pass
return lines
async def push_loop(qdrant: Any, collection: str, get_http) -> None:
while True:
try:
now_ms = int(time.time() * 1000)
body = "\n".join(f"{line} {now_ms}" for line in prometheus_lines(qdrant, collection)) + "\n"
response = await get_http().post(VM_PUSH_URL, content=body, headers={"Content-Type": "text/plain"})
if response.status_code >= 300:
log.warning("metrics push: HTTP %s", response.status_code)
except Exception as exc: # noqa: BLE001
log.warning("metrics push error: %s", exc)
await __import__("asyncio").sleep(VM_PUSH_INTERVAL)