Session 19 — JMeter UI : logs en direct (IHM + Grafana/Loki)¶
Durée : ~4 heures (2 suites)
Contexte : Session focalisée sur l'observabilité des tirs JMeter — logs accessibles
à la fois dans l'IHM JMeter UI et dans Grafana/Loki, sans docker-cli (socket Docker uniquement).
🎯 Objectif de la session¶
Rendre les logs JMeter observables depuis deux points d'entrée :
- IHM JMeter UI : panneau "Logs en direct" avec auto-refresh, deux colonnes (perfshop-jmeter / perfshop-jmeter-ui)
- Grafana/Loki : deux panels dans le dashboard JMeter — logs
perfshop-jmeteretperfshop-jmeter-ui - Contrainte :
perfshop-jmeterfaittail -f /dev/null→ docker logs vide → solution par volume partagé + fichier statique Promtail
📦 Fichiers modifiés¶
| Fichier | Nature |
|---|---|
jmeter-ui/src/server.js |
Endpoint GET /api/logs via socket Docker, -j /jmeter-logs/jmeter.log, try/catch /api/run |
jmeter-ui/public/index.html |
Panneau "Logs en direct", gestion 401 session expirée |
promtail/promtail-config.yml |
Job jmeter-log — lecture fichier statique /jmeter-logs/jmeter.log |
grafana/dashboards/dashboard-jmeter.json |
Panels 105/106/107 — row Logs + panels Loki |
docker-compose.yml + docker-compose.desktop.yml |
Volume ./jmeter/logs:/jmeter-logs sur perfshop-jmeter et perfshop-promtail |
🏗️ Architecture retenue¶
Problème structurel¶
perfshop-jmeter est un container permanent (tail -f /dev/null) — ses logs Docker sont vides.
Deux chemins distincts pour exposer les logs JMeter :
IHM JMeter UI (/api/logs) Grafana/Loki
───────────────────────── ─────────────────────────────────
socket Docker Unix Volume bind mount partagé
└─ POST /containers/exec ./jmeter/logs → /jmeter-logs (rw)
└─ tail -n N /jmeter-logs/ Promtail lit /jmeter-logs/jmeter.log
jmeter.log → push Loki → panel Grafana
Volume partagé¶
# perfshop-jmeter
- ./jmeter/logs:/jmeter-logs # JMeter écrit ici via -j
# perfshop-promtail
- ./jmeter/logs:/jmeter-logs:ro # Promtail lit en lecture seule
Commande JMeter — ajout de -j¶
🔧 Détail des implémentations¶
GET /api/logs — socket Docker Unix (pas de docker-cli)¶
Deux fonctions internes :
dockerExecOutput(container, cmd)—POST /exec+POST /exec/{id}/startavec décodage protocole multiplexé Docker (header 8 octets), flagdoneanti-double-resolvedockerContainerLogs(container)—GET /containers/{id}/logs?stdout=1&stderr=1&tail=N
target |
Source | Méthode |
|---|---|---|
jmeter |
/jmeter-logs/jmeter.log dans le container |
dockerExecOutput + tail -n N |
ui |
Logs stdout du container perfshop-jmeter-ui |
dockerContainerLogs |
both |
Les deux | Les deux |
Promtail — job fichier statique¶
- job_name: jmeter-log
static_configs:
- targets: [localhost]
labels:
job: perfshop-jmeter
container: perfshop-jmeter
__path__: /jmeter-logs/jmeter.log
container: perfshop-jmeter permettent au panel Grafana d'utiliser la même query
{container="perfshop-jmeter"} que les autres containers.
Panneau IHM — "Logs en direct"¶
- Sélecteurs
target(both/jmeter/ui) etlines(50/80/150/300) - Boutons 🔄 Actualiser + ▶ Auto (interval 5s)
- Deux colonnes
<pre>scrollables - Hook
patchLogsOnStatus: auto ON pendant tir, OFF à la fin - Gestion 401 : stop auto silencieux sans reload si écran login visible
🐛 Bugs rencontrés et corrigés¶
| Bug | Cause | Correction |
|---|---|---|
Unexpected token '<' au lancement d'un tir |
Session expirée (401) → HTML Synology renvoyé | Re-login — pas un bug code |
| Reload en boucle au clic login | logsRefresh initial déclenchait window.location.reload() sur 401 |
Vérification loginScreen visible avant reload |
perfshop-jmeter absent de Loki |
Containers non recréés avec --force-recreate |
docker compose up -d --force-recreate |
jmeter/logs/ vide après tir |
server.js non SCP-é → -j absent de la cmd JMeter |
SCP + docker restart perfshop-jmeter-ui |
/api/run retournait HTML 500 |
Handler async sans try/catch → Express error handler HTML |
Try/catch ajouté, JSON propre en cas d'erreur |
✅ Validation finale¶
# Loki indexe bien les deux containers
curl -s "http://localhost:3100/loki/api/v1/label/container/values"
# → ["perfshop-app","perfshop-db","perfshop-frontend","perfshop-jmeter","perfshop-jmeter-ui"]
# Fichier créé après premier tir
ls -la /volume4/docker-speed/perfshop/jmeter/logs/jmeter.log
- ✅ Logs
perfshop-jmeter-uidans Grafana (docker_sd) - ✅ Logs
perfshop-jmeterdans Grafana (fichier statique Promtail) - ✅ Panneau "Logs en direct" dans l'IHM — deux colonnes auto-refresh
- ✅ Compatible Docker Desktop Windows (WSL2 + socket Docker)
- ✅ Compatible NAS Synology DSM 7 (sans docker-cli)
🗂️ Bilan qualité¶
Erreurs Claude :
- Modification inutile try/catch api/run diagnostiquée comme cause du HTML 500 → c'était la session expirée. Modification gardée car défensive et correcte.
- docker compose up -d --no-deps ne recrée pas les containers sans --force-recreate — diagnostic en 2 étapes.
Syndrome "Fix Théorique Sans Validation Empirique" : 0 occurrence — validation NAS à chaque étape.
🎓 Valeur pédagogique¶
| Concept | Ce que l'apprenant voit |
|---|---|
| Observabilité multi-niveaux | Même logs accessibles dans l'IHM et dans Grafana |
| Socket Docker sans CLI | API HTTP Unix socket — fonctionne sur NAS, Docker Desktop, CI |
| Promtail fichier statique | Alternative au docker_sd quand les logs Docker sont vides |
| Volume partagé multi-containers | Pattern producer/consumer via bind mount |
| Gestion session expirée | UX propre — stop auto, pas de boucle reload |