Les erreurs de monitoring qui tuent vos applications en production
Vous avez mis en place Prometheus, Grafana, des dizaines d'alertes. Pourtant, l'incident de production est passé inaperçu pendant deux heures. Le problème n'est pas vos outils, mais comment vous les utilisez. Voici les erreurs classiques qui sabotent votre monitoring.
Erreur 1 : Trop d'alertes, zéro attention
Le problème
Votre canal Slack monitoring reçoit 200 alertes par jour. L'équipe a désactivé les notifications. Quand une vraie alerte critique arrive, personne ne la voit.
Symptômes
- Le canal #alerts a plus de 100 messages non lus
- Les développeurs ont muted le canal
- Les alertes critiques sont noyées dans le bruit
- Personne ne sait quelles alertes sont vraiment importantes
La solution
Règle d'or : une alerte doit déclencher une action humaine.
# AVANT : alerte sur CPU > 80%
- alert: HighCPU
expr: cpu_usage > 80
for: 1m
labels:
severity: warning
# APRÈS : alerte sur impact utilisateur réel
- alert: HighLatency
expr: |
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le)) > 1
for: 5m
labels:
severity: critical
annotations:
summary: "P95 latency exceeded 1s for 5 minutes"
runbook: "https://wiki.company.com/runbooks/high-latency"Pyramide d'alertes :
| Niveau | Critères | Notification | Exemple |
|---|---|---|---|
| P1 Critical | Impact utilisateur direct | PagerDuty + Slack | Site down, paiements échouent |
| P2 Warning | Dégradation potentielle | Slack #alerts | Latence élevée, queue saturée |
| P3 Info | À surveiller | Dashboard uniquement | Disk 70%, scaling proche |
Action immédiate
Faites un audit de vos alertes actuelles :
# Lister toutes les alertes déclenchées cette semaine
promtool query instant 'ALERTS{alertstate="firing"}' | wc -l
# Ratio alertes actionnées vs ignorées ?Si moins de 20% de vos alertes ont mené à une action, vous avez un problème.
Erreur 2 : Surveiller les mauvaises métriques
Le problème
Vous surveillez l'utilisation CPU de vos pods, mais pas le temps de réponse vu par l'utilisateur. Quand le CPU est à 90%, votre application fonctionne peut-être très bien. Quand il est à 20%, elle peut être complètement cassée.
Les métriques qui comptent vraiment (USE et RED)
Méthode RED pour les services :
| Métrique | Question | Exemple Prometheus |
|---|---|---|
| Rate | Combien de requêtes/s ? | rate(http_requests_total[5m]) |
| Errors | Quel % d'erreurs ? | rate(http_requests_total{status=~"5.."}[5m]) |
| Duration | Combien de temps ? | histogram_quantile(0.95, ...) |
Méthode USE pour les ressources :
| Métrique | Question | Exemple |
|---|---|---|
| Utilization | Quelle proportion utilisée ? | CPU usage % |
| Saturation | Y a-t-il de la contention ? | Queue depth, waiting threads |
| Errors | Y a-t-il des erreurs système ? | Disk errors, network drops |
Ce qu'il faut surveiller en priorité
# Groupe 1 : Impact utilisateur (RED)
- record: service:http_requests:rate5m
expr: sum(rate(http_server_requests_seconds_count[5m])) by (service)
- record: service:http_errors:rate5m
expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) by (service)
- record: service:http_latency:p95
expr: histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, service))
# Groupe 2 : Saturation (avant que ça ne casse)
- record: service:queue_saturation
expr: sum(queue_length) by (service) / sum(queue_capacity) by (service)
- record: service:connection_pool_saturation
expr: hikaricp_connections_active / hikaricp_connections_maxMétriques business à ne pas oublier
// Ne surveillez pas que la technique
@Component
public class BusinessMetrics {
private final MeterRegistry registry;
@EventListener
public void onOrderCompleted(OrderCompletedEvent event) {
// Métrique business : conversions
registry.counter("orders.completed",
"payment_method", event.getPaymentMethod(),
"plan", event.getPlan()
).increment();
// Métrique business : revenu
registry.summary("orders.revenue",
"currency", event.getCurrency()
).record(event.getAmount());
}
@EventListener
public void onOrderFailed(OrderFailedEvent event) {
// Métrique business : pertes potentielles
registry.counter("orders.failed",
"reason", event.getReason()
).increment();
}
}Erreur 3 : Dashboards illisibles
Le problème
Votre dashboard principal affiche 47 graphiques. Personne ne sait où regarder en cas d'incident. Le temps de compréhension est de 10 minutes au lieu de 10 secondes.
Avant/Après
Dashboard chaotique :
- 47 panneaux sans organisation
- Métriques techniques et business mélangées
- Pas de hiérarchie visuelle
- Timeframes différents sur chaque panel
Dashboard efficace :
- 6-8 panneaux maximum
- Organisation hiérarchique (haut = critique)
- Code couleur cohérent (vert = OK, rouge = problème)
- Même timeframe partout
Structure recommandée
┌────────────────────────────────────────────────┐
│ SANTÉ GLOBALE │
│ [🟢 API] [🟢 DB] [🟢 Cache] [🟡 Queue] │
└────────────────────────────────────────────────┘
┌─────────────────────┬──────────────────────────┐
│ TRAFFIC │ ERREURS │
│ [Requêtes/s graph] │ [Error rate graph] │
│ 1,250 req/s │ 0.02% │
└─────────────────────┴──────────────────────────┘
┌─────────────────────┬──────────────────────────┐
│ LATENCE P95 │ SATURATION │
│ [Latency graph] │ [CPU/Mem/Queue graphs] │
│ 45ms │ CPU: 35% | Mem: 60% │
└─────────────────────┴──────────────────────────┘Dashboard par niveau
| Dashboard | Audience | Contenu |
|---|---|---|
| Executive | Direction | KPIs business, disponibilité, coûts |
| Operations | SRE/Ops | Santé services, alertes actives, capacité |
| Debug | Développeurs | Métriques détaillées, logs, traces |
Grafana best practices
{
"dashboard": {
"title": "Production - Vue Opérationnelle",
"refresh": "30s",
"time": {
"from": "now-1h",
"to": "now"
},
"panels": [
{
"title": "Santé Services",
"type": "stat",
"gridPos": { "h": 4, "w": 24, "x": 0, "y": 0 },
"options": {
"colorMode": "background",
"graphMode": "none"
}
}
]
}
}Erreur 4 : Pas de runbooks
Le problème
L'alerte "Database connection pool exhausted" se déclenche à 3h du matin. Le développeur d'astreinte ne connaît pas ce système. Il passe 45 minutes à comprendre quoi faire.
Ce qu'un runbook doit contenir
# Alerte : Database Connection Pool Exhausted
## Symptômes
- Alerte `HikariPoolExhausted` déclenchée
- Requêtes en timeout
- Erreurs 503 sur l'API
## Impact
- P1 : Les utilisateurs ne peuvent pas se connecter
- Services affectés : auth-service, user-service
## Diagnostic rapide (< 2 min)
1. Vérifier le dashboard connexions :
https://grafana.company.com/d/db-connections
2. Vérifier les requêtes lentes :
```sql
SELECT pid, query, state, wait_event
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;
```
3. Vérifier les locks :
```sql
SELECT * FROM pg_locks WHERE NOT granted;
```
## Actions immédiates
### Si requêtes lentes identifiées
1. Killer les requêtes problématiques :
```sql
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE query LIKE '%problematic_query%';
```
### Si charge excessive
1. Scale horizontalement :
```bash
kubectl scale deployment api --replicas=10
```
2. Activer le circuit breaker :
```bash
kubectl set env deployment/api CIRCUIT_BREAKER_ENABLED=true
```
## Escalade
- Si non résolu en 15 min : contacter @dba-team
- Si P1 prolongé : incident call avec @sre-lead
## Post-incident
- Créer un ticket d'analyse
- Mettre à jour ce runbook si nécessaireAutomatiser les runbooks
# Prometheus alert avec lien runbook
- alert: DatabasePoolExhausted
expr: hikaricp_connections_active >= hikaricp_connections_max * 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "Connection pool at {{ $value }}% capacity"
runbook_url: "https://wiki.company.com/runbooks/db-pool-exhausted"
dashboard_url: "https://grafana.company.com/d/db-connections"Erreur 5 : Ignorer les logs structurés
Le problème
Vos logs ressemblent à ça :
2026-01-16 10:30:00 ERROR Something went wrong processing request
2026-01-16 10:30:01 INFO Request completedImpossible de filtrer, d'agréger, de corréler.
La solution : logs JSON structurés
{
"@timestamp": "2026-01-16T10:30:00.000Z",
"level": "ERROR",
"logger": "com.company.OrderService",
"message": "Failed to process order",
"trace_id": "abc123def456",
"span_id": "789xyz",
"order_id": "ORD-12345",
"customer_id": "CUST-67890",
"error_type": "PaymentDeclinedException",
"error_message": "Card declined",
"service": "order-service",
"environment": "production",
"kubernetes": {
"pod": "order-service-7d9f8b6c5-x2k4n",
"namespace": "production"
}
}Configuration Spring Boot
<!-- logback-spring.xml -->
<configuration>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>trace_id</includeMdcKeyName>
<includeMdcKeyName>span_id</includeMdcKeyName>
<includeMdcKeyName>order_id</includeMdcKeyName>
<customFields>
{
"service": "${SPRING_APPLICATION_NAME:-unknown}",
"environment": "${ENVIRONMENT:-dev}"
}
</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON"/>
</root>
</configuration>Requêtes Loki efficaces
# Toutes les erreurs d'un utilisateur spécifique
{service="order-service"} | json | customer_id="CUST-67890" | level="ERROR"
# Erreurs groupées par type
sum by (error_type) (count_over_time({service="order-service"} | json | level="ERROR" [1h]))
# Latence des requêtes par endpoint
avg by (endpoint) (
{service="order-service"} | json | unwrap duration_ms
)Erreur 6 : Pas de corrélation logs/traces/métriques
Le problème
Vous voyez un spike de latence dans Grafana. Vous cherchez dans les logs. Impossible de trouver les requêtes correspondantes. Vous perdez 30 minutes à faire le lien manuellement.
La solution : Trace ID partout
@RestController
public class OrderController {
private static final Logger log = LoggerFactory.getLogger(OrderController.class);
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
// Le trace ID est automatiquement ajouté via MDC par OpenTelemetry
String traceId = Span.current().getSpanContext().getTraceId();
log.info("Creating order for customer {}", request.getCustomerId());
try {
Order order = orderService.create(request);
log.info("Order {} created successfully", order.getId());
return ResponseEntity.ok(order);
} catch (Exception e) {
log.error("Failed to create order: {}", e.getMessage());
throw e;
}
}
}Dashboard avec liens
{
"panels": [
{
"title": "Error Rate",
"type": "graph",
"options": {
"dataLinks": [
{
"title": "View traces in Jaeger",
"url": "https://jaeger.company.com/trace/${__data.fields.trace_id}"
},
{
"title": "View logs in Loki",
"url": "https://grafana.company.com/explore?expr={trace_id=\"${__data.fields.trace_id}\"}"
}
]
}
}
]
}Erreur 7 : Oublier la baseline
Le problème
Vous recevez une alerte "CPU à 85%". Est-ce un problème ? Impossible de savoir si c'est normal à cette heure-ci ou si c'est anormal.
La solution : comparer à l'historique
# Alerte basée sur la déviation par rapport à la normale
- alert: AnomalyHighLatency
expr: |
http_request_duration_seconds:p95 >
avg_over_time(http_request_duration_seconds:p95[7d] offset 1h) * 1.5
for: 10m
annotations:
summary: "Latency 50% higher than usual for this time"Métriques de baseline
# P95 latence moyenne sur 7 jours, même heure
avg_over_time(
http_request_duration_seconds:p95[7d] offset 1h
)
# Traffic attendu (comparaison semaine précédente)
http_requests_total / http_requests_total offset 7d
# Comparaison jour précédent
increase(http_requests_total[1h]) / increase(http_requests_total[1h] offset 1d)Checklist monitoring efficace
Avant de considérer votre monitoring comme "prêt pour la production" :
- ☐ Moins de 10 alertes par jour en moyenne
- ☐ Chaque alerte a un runbook associé
- ☐ Métriques RED/USE implémentées
- ☐ Logs structurés en JSON
- ☐ Corrélation trace_id dans logs/métriques/traces
- ☐ Dashboard principal lisible en < 10 secondes
- ☐ Baselines définies pour les alertes
- ☐ Équipe formée aux runbooks
- ☐ Tests réguliers des alertes (chaos engineering)
- ☐ Revue mensuelle des alertes ignorées
Plan d'action immédiat
- Semaine 1 : Audit des alertes actuelles
- Désactiver les alertes ignorées depuis > 1 mois
- Classifier les alertes restantes (P1/P2/P3)
- Semaine 2 : Restructurer les dashboards
- Créer un dashboard opérationnel avec 6-8 panneaux
- Ajouter les métriques RED manquantes
- Semaine 3 : Documentation
- Écrire un runbook pour chaque alerte P1
- Lier les runbooks aux alertes
- Semaine 4 : Corrélation
- Implémenter les logs structurés
- Ajouter le trace_id partout
- Créer les liens entre dashboards/logs/traces
Conclusion
Un bon monitoring n'est pas une question d'outils, mais de discipline. Moins d'alertes mais plus pertinentes. Des dashboards lisibles en quelques secondes. Des runbooks pour chaque scénario. Et surtout, une corrélation entre toutes vos sources de données.
Commencez par auditer vos alertes actuelles. Si plus de 50% sont ignorées, vous avez un problème à résoudre avant d'ajouter quoi que ce soit.
Pour mettre en place l'observabilité : Observabilité en production : logs, métriques et traces avec OpenTelemetry
Pour comprendre pourquoi vos projets échouent : Pourquoi votre RAG échoue (et comment le corriger)