144 lines
5.1 KiB
Python
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,
|
|
}
|