Files
ObsiGate/backend/routers/health.py
T

144 lines
5.1 KiB
Python

"""System health endpoints (ROADMAP #85, tranche 1).
Handlers déplacés depuis :mod:`backend.main` sans changement de
comportement : mêmes chemins (``/api/health``, ``/api/health/detailed``),
même ``response_model`` (:class:`backend.schemas.HealthResponse`), même
dépendance admin. Seule différence : la version est lue via
:func:`backend.version.get_version` au lieu de ``app.version`` (valeur
identique, figée au démarrage depuis le fichier ``VERSION``).
Note : ``uptime_seconds`` reprend l'expression d'origine
(``'_SERVER_START_TIME' in globals()``), qui vaut toujours 0 — le global
n'est défini nulle part dans ``backend.main`` (voir ``backend.admin`` qui
possède son propre compteur). Ce comportement est préservé tel quel ; le
corriger fera l'objet d'une tranche ultérieure avec test dédié.
"""
from fastapi import APIRouter, Depends
from backend.auth.middleware import require_admin
from backend.indexer import index
from backend.schemas import HealthResponse
from backend.version import get_git_commit, get_git_describe, get_version
router = APIRouter(tags=["System"])
@router.get("/api/health", response_model=HealthResponse)
async def api_health():
"""Health check endpoint for Docker and monitoring.
Returns:
Application status, version, vault count and total file count.
"""
total_files = sum(len(v["files"]) for v in index.values())
total_tokens = sum(len(v.get("files", [])) * 1000 for v in index.values()) # rough approx
import time
from backend.indexer import _last_full_index_ts
# `_SERVER_START_TIME` n'existe dans aucun module (comportement d'origine
# préservé : uptime toujours 0 — voir docstring du module).
uptime = int(time.time() - _SERVER_START_TIME) if '_SERVER_START_TIME' in globals() else 0 # noqa: F821
return {
"status": "ok",
"version": get_version(),
"vaults": len(index),
"total_files": total_files,
"total_tokens": total_tokens,
"last_full_index_ts": _last_full_index_ts,
"uptime_seconds": uptime,
"git_describe": get_git_describe(),
"git_commit": get_git_commit(),
}
@router.get("/api/health/detailed", response_model=HealthResponse)
async def api_health_detailed(current_user=Depends(require_admin)):
"""Detailed health check — admin only.
Returns enriched metrics including memory, disk, SSE connections, and backup stats.
"""
import psutil
from backend.admin import _count_active_sessions, _get_disk_stats
from backend.indexer import _last_full_index_ts, index
total_files = sum(len(v["files"]) for v in index.values())
total_tokens = sum(len(v.get("files", [])) * 1000 for v in index.values())
import time
uptime = int(time.time() - _SERVER_START_TIME) if '_SERVER_START_TIME' in globals() else 0 # noqa: F821 — voir ci-dessus
# Memory
vm = psutil.virtual_memory()
mem_used_mb = round(vm.used / (1024 ** 2), 1)
mem_total_mb = round(vm.total / (1024 ** 2), 1)
mem_pct = round(vm.percent, 1)
# CPU
cpu_pct = psutil.cpu_percent(interval=None)
# Disk
disk_used_gb, disk_total_gb = _get_disk_stats()
disk_free_gb = round(disk_total_gb - disk_used_gb, 2)
disk_pct = round((disk_used_gb / disk_total_gb * 100) if disk_total_gb > 0 else 0, 1)
# SSE connections (approximation)
active_sessions = _count_active_sessions()
# Backups
from backend.admin import _scan_backups
backup_rows = _scan_backups()
total_backups = len(backup_rows)
total_backup_size_mb = round(sum(r["size"] for r in backup_rows) / (1024 ** 2), 2)
oldest_backup_age_days = 0.0
if backup_rows:
now_ts = int(time.time())
oldest_ts = min(r["timestamp"] for r in backup_rows)
oldest_backup_age_days = round((now_ts - oldest_ts) / 86400, 2)
# Index details
index_detail = {}
for name, data in index.items():
index_detail[name] = {
"file_count": len(data["files"]),
"tag_count": len(data.get("tags", [])),
"token_count_approx": len(data.get("files", [])) * 1000,
}
return {
"status": "ok",
"version": get_version(),
"vaults": len(index),
"total_files": total_files,
"total_tokens": total_tokens,
"last_full_index_ts": _last_full_index_ts,
"uptime_seconds": uptime,
"git_describe": get_git_describe(),
"git_commit": get_git_commit(),
# Enriched fields
"memory": {
"used_mb": mem_used_mb,
"total_mb": mem_total_mb,
"percent": mem_pct,
},
"cpu": {
"percent": cpu_pct,
},
"disk": {
"used_gb": disk_used_gb,
"total_gb": disk_total_gb,
"free_gb": disk_free_gb,
"percent": disk_pct,
},
"connections": {
"active_sse": active_sessions,
},
"backups": {
"total_count": total_backups,
"total_size_mb": total_backup_size_mb,
"oldest_age_days": oldest_backup_age_days,
},
"index": index_detail,
}