Files
SIRH/doc/error-tracking.md
T
matthieu 42b02a8148
Auto Tag Develop / tag (push) Successful in 9s
feat : error tracking backend vers GlitchTip (via Tailscale) (#37)
## Objectif
Remonter les erreurs **backend** Symfony vers **GlitchTip** (SDK Sentry), **prod uniquement**, **inerte sans `SENTRY_DSN`**. Transport réseau via **Tailscale** sur le host de prod (infra, hors repo). Frontend hors périmètre.

## Contenu
- `sentry/sentry-symfony:^5.10` (+ `symfony.lock` recipe)
- `config/bundles.php` → `SentryBundle ['prod' => true]`
- `config/packages/sentry.yaml` (nouveau) : DSN runtime, release `%app.version%`, 4xx ignorés, pas de tracing, handler Monolog ERROR+
- `config/packages/monolog.yaml` : handler `sentry` en `when@prod`
- `.env` : bloc `SENTRY_DSN` documenté (vide → inerte)
- `doc/error-tracking.md` (runbook Tailscale) + section `CLAUDE.md`
- Spec + plan sous `docs/superpowers/`

## Vérifications
- Prod `cache:clear` OK, service `Sentry\Monolog\Handler` chargé
- **267/267 tests verts**, dev/test inchangés (bundle non chargé hors prod)
- Aucun changement `frontend/` / `.gitea/` / `deploy/docker/`
- Revue multi-agents : **READY TO MERGE** (aucun Critical/Important)

## Activation prod (hors code, cf. `doc/error-tracking.md`)
1. Tailscale sur l'hôte GlitchTip **et** sur le VPS OVH (prod)
2. Créer le projet `sirh-api` dans GlitchTip → récupérer le DSN
3. `SENTRY_DSN=http://<clé>@<IP-tailnet>:<port>/<id>` dans l'env_file serveur + redéploiement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #37
Co-authored-by: matthieu <matthieu@yuno.malio.fr>
Co-committed-by: matthieu <matthieu@yuno.malio.fr>
2026-06-28 11:46:35 +00:00

5.4 KiB

Error tracking (GlitchTip)

Les erreurs backend (Symfony) sont remontées vers GlitchTip (instance interne MALIO, compatible SDK Sentry), org malio, projet sirh-api. Prod uniquement, inerte sans DSN.

Frontend hors périmètre (les erreurs front partent du navigateur RH ; ajout futur possible via un proxy nginx /ingest).

Contrainte réseau & transport

GlitchTip est sur le réseau interne (bloqué par Sophos), servi en HTTPS sur logs.malio-dev.fr (cert auto-signé par la CA interne « MALIO-DEV Local Root CA »). SIRH tourne sur un VPS OVH public. Le lien passe par un tunnel Tailscale entre les deux hôtes.

Topologie retenue (Option A — HTTPS + hostname mappé sur le tailnet) :

  • Tailscale est installé sur l'hôte GlitchTip (IP tailnet 100.111.223.34) et sur le VPS OVH (IP tailnet 100.93.52.45).
  • Le DSN reste inchangé : https://<clé>@logs.malio-dev.fr/<id> (même endpoint que le navigateur → pas de souci ALLOWED_HOSTS, Host header et cert cohérents).
  • Côté SIRH, le nom logs.malio-dev.fr est résolu vers l'IP tailnet de GlitchTip via extra_hosts dans le docker-compose du serveur.
  • La CA racine MALIO est bakée dans l'image SIRH (deploy/docker/Dockerfile.prod) pour que le SDK accepte le TLS auto-signé.

Pré-requis : le nginx qui sert logs.malio-dev.fr en 443 doit écouter sur une interface joignable via le tailnet (typiquement 0.0.0.0:443 → joignable sur 100.111.223.34:443).

Fichiers concernés

Fichier Rôle
config/packages/sentry.yaml conf backend (prod-only, DSN runtime, 4xx ignorés, release = app.version, handler Monolog ERROR+)
config/bundles.php SentryBundle enregistré ['prod' => true]
config/packages/monolog.yaml handler sentry (service) en when@prod
.env bloc documenté SENTRY_DSN (vide → inerte)
deploy/docker/Dockerfile.prod bake la CA racine MALIO (update-ca-certificates) pour le TLS interne
deploy/docker/malio-dev-root-ca.crt certificat public de la CA interne (aucune clé privée)

Activation (runbook)

  1. Tailscale sur les deux hôtes (GlitchTip et VPS OVH) :
    curl -fsSL https://tailscale.com/install.sh | sh
    sudo tailscale up            # ou --authkey tskey-auth-XXXX (headless)
    tailscale ip -4              # GlitchTip → 100.111.223.34 ; OVH → 100.93.52.45
    
  2. Vérifier l'accès depuis le VPS OVH (tunnel + nginx 443 de GlitchTip) :
    tailscale ping 100.111.223.34
    curl -sSk -o /dev/null -w "%{http_code}\n" https://100.111.223.34/   # réponse HTTP = tunnel OK
    
  3. Mapper le hostname vers l'IP tailnet dans le docker-compose du serveur OVH (service php), pour que le container résolve logs.malio-dev.fr :
    extra_hosts:
      - "logs.malio-dev.fr:100.111.223.34"
    
  4. Projet GlitchTip : déjà créé (org malio, projet sirh-api, id 3). DSN de base affiché dans Settings → Client Keys : https://<clé>@logs.malio-dev.fr/3.
  5. Injecter le DSN tel quel (hostname conservé) dans l'env_file serveur (pas dans l'image), puis rebuild/redéployer l'image (la CA est bakée au build) :
    SENTRY_DSN=https://<clé>@logs.malio-dev.fr/3
    
    docker compose up -d
    docker compose exec php php bin/console cache:clear --env=prod
    

Tester l'envoi

Le bundle sentry/sentry-symfony fournit une commande qui envoie un événement de test et confirme s'il est bien parti vers GlitchTip. Elle n'existe qu'en prod (bundle prod-only) et nécessite SENTRY_DSN défini.

# Sur le serveur, dans le container PHP (SENTRY_DSN doit être dans l'env) :
docker compose exec php sh -lc "APP_ENV=prod php bin/console sentry:test"

Sortie attendue : Sending test message... done. → une Issue de test apparaît dans le projet sirh-api côté GlitchTip. Si l'envoi échoue (Message not sent), le problème est réseau (Tailscale/route/port) ou DSN, pas applicatif.

Pré-check connectivité depuis le VPS OVH (-k ignore le cert juste pour ce test) :

tailscale ping 100.111.223.34
curl -sSk -o /dev/null -w "%{http_code}\n" https://100.111.223.34/   # réponse HTTP = tunnel OK
# Avec résolution du hostname (comme le container) + validation par la CA :
curl --resolve logs.malio-dev.fr:443:100.111.223.34 \
     --cacert deploy/docker/malio-dev-root-ca.crt \
     -sS -o /dev/null -w "%{http_code}\n" https://logs.malio-dev.fr/

Alternative sans commande dédiée : déclencher un throw new \RuntimeException('glitchtip test') temporaire dans un endpoint, ou un $logger->error('glitchtip test') (niveau ERROR+ → Issue).

CA HTTPS interne (bakée dans l'image)

GlitchTip est en HTTPS avec un cert auto-signé par la CA interne MALIO. Le SDK refuse un TLS non approuvé (« Message not sent »). La CA publique (deploy/docker/malio-dev-root-ca.crt, aucune clé privée) est donc installée dans le trust store de l'image au build (deploy/docker/Dockerfile.prod, stage production) :

COPY deploy/docker/malio-dev-root-ca.crt /usr/local/share/ca-certificates/malio-dev-root-ca.crt
RUN update-ca-certificates

Combinée à l'extra_hosts (hostname → IP tailnet), le container fait confiance à logs.malio-dev.fr et l'atteint via le tunnel.

Design détaillé : docs/superpowers/specs/2026-06-28-glitchtip-backend-error-tracking-design.md.