File size: 6,466 Bytes
d0a3fab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# 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] <event> <key=value>`
   (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) |