HealthCheck & Debug Toolbar

HealthCheck & Debug Toolbar

Deux outils bien distincts : HealthCheck répond « est-ce que ça tourne maintenant ? » (supervision), la Debug Toolbar répond « qu'est-ce que cette requête a fait ? » (développement).

HealthCheck

Niang\Core\HealthCheck::run() est la logique partagée entre GET /health (et son alias /up) et niang health en CLI — une seule vérification, deux façades. Quatre services testés en conditions réelles, pas juste « le fichier de config existe » :

ServiceVérification réelle
databaseSELECT 1 sur la connexion configurée
cacheécrit puis relit une clé (Cache::put()/get())
storagestorage/ existe et est accessible en écriture
queueQueue::pending() ne lève pas d'exception
bash
curl http://localhost:8000/health
text
{"status":"ok","services":{"database":"ok","cache":"ok","storage":"ok","queue":"ok"}}

Statut HTTP 200 si tout est ok, 503 sinon — pensé pour un check de load balancer ou un outil de supervision (Uptime Kuma...), à brancher directement. Équivalent en CLI, pour vérifier avant un déploiement sans faire de requête HTTP :

bash
./bin/niang health

À ne pas confondre avec niang doctor : doctor vérifie l'environnement statique (version PHP, extensions chargées, .env présent, APP_KEY configurée, permissions d'écriture, routes chargeables) — utile juste après une installation ou un déploiement. health/HealthCheck vérifie l'état d'exécution — ces services répondent-ils maintenant ?

Sondes live et ready

RouteVérifieUsage
GET /health, /up, /health/readybase, cache, stockage, file d'attente ; 503 si l'un échouesupervision, sonde readiness
GET /health/liverien : le process PHP répondsonde liveness (redémarrer un conteneur bloqué)

Les quatre routes restent accessibles en mode maintenance.

Observabilité

Identifiant de requête et traces

Chaque réponse porte un en-tête X-Request-Id, ajouté aussi à chaque ligne de log écrite pendant la requête : une erreur signalée par un utilisateur se retrouve dans les logs à partir de cet identifiant. Un identifiant fourni par le répartiteur de charge (X-Request-Id, 8 à 128 caractères sûrs) est conservé. Un job mis en file garde celui de la requête qui l'a créé.

Le framework suit W3C Trace Context : un en-tête traceparent entrant (proxy, APM, collecteur OpenTelemetry) est rejoint, et les appels de Http\Client (webhooks, OAuth, S3) le transmettent au service appelé. Sans SDK : l'outil placé devant l'application relie ses traces aux logs.

php
use Niang\Core\Log;
use Niang\Core\Trace;

Log::withContext(['user_id' => $user['id']]);   // ajouté à tous les messages suivants
Trace::requestId();                              // pour l'afficher sur une page d'erreur, par exemple

Logs JSON

.env
LOG_FORMAT=json
LOG_CHANNEL=stderr   # conteneurs ; ou daily, syslog...
json
{"timestamp":"2026-09-27T13:34:33.500+00:00","level":"info","message":"commande 7 créée","context":{"id":7},"request_id":"4bf92f3577b34da6a3ce929d0e0e4736"}

Un objet par ligne, pour Loki, Elasticsearch, CloudWatch ou Datadog. Une exception passée en contexte garde sa classe, son message et son emplacement ; les clés sensibles restent masquées. line (défaut) garde le format lisible.

Métriques Prometheus

.env
METRICS_ENABLED=true
METRICS_TOKEN=une-longue-valeur-aleatoire
prometheus.yml
scrape_configs:
  - job_name: niangpro
    scheme: https
    authorization:
      credentials: une-longue-valeur-aleatoire
    static_configs:
      - targets: ['app.exemple.sn']
MétriqueType
niangpro_http_requests_total{method, status}compteur (statut par classe : 2xx, 5xx...)
niangpro_http_request_duration_secondshistogramme
niangpro_jobs_processed_total, niangpro_jobs_failed_totalcompteurs (workers)
app_*vos compteurs et jauges
php
// config/metrics.php
'counters' => ['orders_created_total' => 'Commandes créées'],

// dans le code
Metrics::increment('orders_created_total');

// dans AppServiceProvider::boot() : calculée à chaque lecture
Metrics::gauge('jobs_pending', 'Jobs en attente', fn () => DB::table('jobs')->count());

Sans METRICS_TOKEN, /metrics répond 404 : jamais exposé par défaut. Les compteurs sont dans le cache : avec plusieurs serveurs, CACHE_DRIVER=database ou redis les partage ; cache:clear les remet à zéro, ce que Prometheus traite comme un redémarrage. Aucune étiquette par URL : le nombre de séries reste fixe. niang doctor signale des métriques activées sans jeton.

Debug Toolbar

Injectée automatiquement en bas de chaque réponse HTML quand APP_DEBUG=true (voir cycle de vie d'une requête, Application::handle()) : temps de réponse, nombre de requêtes SQL exécutées (DB::queryCount(), remis à zéro à chaque requête), pic mémoire, code de statut. Visible sur toutes les pages de cette documentation en développement local.

Trois conditions doivent toutes être vraies pour qu'elle s'injecte — jamais sur une réponse qu'elle risquerait de corrompre :

  • APP_DEBUG=true dans .env.
  • La réponse a un Content-Type qui commence par text/html — jamais sur du JSON.
  • Le corps contient une balise </body> où s'accrocher (la barre est insérée juste avant).

APP_DEBUG=false en production — sans quoi la barre de debug s'affiche à vos visiteurs. niang doctor avertit (sans faire échouer) si APP_ENV=production et APP_DEBUG=true sont actifs en même temps.

⏱ 8.67 ms 🗄 0 requête(s) SQL 🧠 4.00 MB ↩ 200