# Observabilité — Picarones > **Audience** : opérateur (DSI institutionnelle, SRE). Décrit > comment instrumenter Picarones pour qu'il soit observable depuis > Prometheus, Grafana, Loki, Datadog, etc. > > Pour la réponse aux incidents, voir [`runbook.md`](runbook.md). > Pour le déploiement, voir [`deployment-institutional.md`](deployment-institutional.md). ## Principes Picarones expose trois types de signaux : 1. **Logs structurés** (stdlib `logging`). Tous les modules utilisent `logger = logging.getLogger(__name__)`. Niveaux conventionnels : DEBUG, INFO, WARNING, ERROR. Aucun `print` en production. 2. **Audit trail** spécifique : `[audit] ` (par convention). Émis par les endpoints sensibles (`POST/DELETE /api/jobs`). 3. **Endpoints de santé** : `GET /health`, `GET /version`. L'export vers une plateforme observabilité (Prometheus, Datadog, ELK) est laissé au déploiement institutionnel — Picarones ne pousse rien de lui-même. ## Logs structurés ### Format recommandé Configurer le root logger en JSON pour l'ingestion automatique : ```python # /etc/picarones/logging.yaml version: 1 disable_existing_loggers: false formatters: json: format: '{"ts":"%(asctime)s","lvl":"%(levelname)s","logger":"%(name)s","msg":"%(message)s"}' handlers: stdout: class: logging.StreamHandler stream: ext://sys.stdout formatter: json loggers: picarones: level: INFO handlers: [stdout] propagate: false root: level: WARNING handlers: [stdout] ``` Activer au démarrage : ```bash PICARONES_LOG_CONFIG=/etc/picarones/logging.yaml \ uvicorn picarones.interfaces.web:create_app --factory ... ``` ### Niveaux par module | Module | Niveau prod recommandé | |--------|------------------------| | `picarones.adapters.*` | INFO | | `picarones.app.services.*` | INFO | | `picarones.interfaces.web.*` | INFO | | `picarones.pipeline.*` | INFO (DEBUG si chasse à un bug d'orchestration) | | `picarones.evaluation.*` | WARNING (très verbeux en INFO) | | `picarones.adapters._retry` | WARNING (déjà bavard sur les retries) | ### Exemples de lignes utiles à monitorer | Pattern | Signification | Alerte | |---------|---------------|--------| | `[adapter] erreur retryable.*` | Cloud API instable | > 10/min sur 5 min → page | | `OCRAdapterError` | Échec définitif d'OCR | > 5/min → warning | | `[job_runner] job .* en échec` | Job s'est terminé en error | track per-IP | | `[audit] job_submitted` | Soumission de job | tracker pour audit RGPD | | `[audit] job_cancelled` | Annulation de job | tracker pour audit RGPD | | `WinError 87` | Filename Windows invalide | DEVRAIT être 0 (corrigé S59) — sinon régression | | `database is locked` | SQLite contention | > 1/min → page | ## Audit trail Les opérations sensibles produisent un log INFO normalisé : ``` INFO [audit] job_submitted job_id=abc123 corpus=bnf_xviii from=10.0.0.42 INFO [audit] job_cancelled job_id=abc123 from=10.0.0.42 ``` Ces lignes sont **destinées à être conservées** selon la politique RGPD de l'institution (cf. [`data-retention-rgpd.md`](data-retention-rgpd.md)). Stockage minimum recommandé : 90 jours (audit interne) ; 5 ans si soumis aux Archives nationales. Pour ingestion SIEM : ``` filter '[audit] ' extract job_id, corpus, from forward to siem.bnf.fr:514 (syslog) ``` ## Endpoints de santé ### `GET /health` Réponse `200 OK` si le process est en mesure de servir. Vérifie : - `JobStore` accessible (lecture) - `WorkspaceManager` accessible (écriture sandbox) - Pas de check sur les API cloud (un cloud down ne doit pas planter les health probes locales) ```json { "status": "ok", "version": "1.3.0-dev", "job_store": "ok", "workspace": "ok" } ``` À utiliser comme **liveness probe** (Kubernetes) ou **healthcheck** (Docker). Recommandation : every 30s, fail after 3 consecutive. ### `GET /version` Réponse : ```json { "version": "1.3.0-dev", "code_version": "git-sha-abc1234", "python": "3.11.15" } ``` Utile pour déterminer la version déployée sans accès au filesystem. ## Métriques (à venir) Picarones n'expose pas encore d'endpoint Prometheus `/metrics`. Recommandation immédiate : monitorer les logs. **Backlog** (cf. [`/docs/roadmap/backlog.md`](../roadmap/backlog.md)) : - Compteur `picarones_jobs_total{status="complete|error|cancelled"}` - Histogramme `picarones_job_duration_seconds` - Compteur `picarones_adapter_calls_total{adapter, status}` - Histogramme `picarones_adapter_latency_seconds{adapter}` - Gauge `picarones_jobs_running` (instantané) Implémentation visée : `prometheus_client` middleware FastAPI optionnel. ## Tracing distribué Pour les institutions qui orchestrent Picarones avec d'autres services (ETL, cataloguing), le tracing OpenTelemetry est recommandé. État actuel : pas d'instrumentation native. Une instrumentation opportuniste via `opentelemetry-instrumentation-fastapi` peut être activée par le déploiement sans modifier Picarones : ```python from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor from picarones.interfaces.web import create_app app = create_app(state=...) FastAPIInstrumentor.instrument_app(app) ``` ## Dashboards Grafana — squelette Les panels recommandés pour un dashboard Picarones : 1. **Jobs throughput** — courbes par status (complete/error/cancelled), stack area, 24 h. 2. **Adapter latency p50/p95/p99** par adapter (Tesseract, Pero, Mistral OCR, Google Vision, Azure DI, OpenAI, Anthropic, Mistral chat, Ollama). 3. **Error rate par adapter** — % d'erreurs sur la dernière heure. 4. **Concurrence** — `picarones_jobs_running` actuel, comparé à `PICARONES_MAX_CONCURRENT_JOBS`. 5. **Workspace size** — `du -sh /var/lib/picarones/workspaces` via exporter node. 6. **Heap RSS** du process Picarones (via node_exporter ou process_exporter). ## SLOs suggérés Pour un déploiement institutionnel ouvert aux chercheurs : | Métrique | SLO 30j | Action si dépassé | |----------|---------|-------------------| | Disponibilité `/health` | 99.5 % | Investiguer infra | | Job completion rate | > 95 % | Examiner taux d'erreurs adapter | | API p95 latency (CRUD jobs) | < 500 ms | Profiler le `JobStore` | | Cloud adapter retry rate | < 5 % | Demander quota plus haut | ## Révisions | Version | Date | Changements | |---------|------|-------------| | 1.0 | 2026-05 | Création initiale (S60) |