"""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)