Logs et CloudWatch pour Lambda
Introduction
Les logs sont essentiels pour comprendre le comportement de vos fonctions Lambda et diagnostiquer les problemes. Amazon CloudWatch Logs est le service natif pour collecter, stocker et analyser ces logs.
Architecture des Logs Lambda
┌─────────────────────────────────────────────────────────────────┐
│ FLUX DES LOGS LAMBDA │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Lambda │────►│ CloudWatch │────►│ Analyse │ │
│ │ Function │ │ Logs │ │ / Alertes │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Chaque invocation genere : │
│ • START RequestId │
│ • Vos logs (print, console.log) │
│ • END RequestId │
│ • REPORT (duree, memoire, facturation) │
│ │
└─────────────────────────────────────────────────────────────────┘
Structure des Log Groups
CloudWatch Logs
│
├── /aws/lambda/ma-fonction-1
│ ├── Log Stream 2024/01/15/[$LATEST]abc123
│ ├── Log Stream 2024/01/15/[$LATEST]def456
│ └── Log Stream 2024/01/16/[$LATEST]ghi789
│
├── /aws/lambda/ma-fonction-2
│ └── ...
│
└── /aws/lambda/ma-fonction-3
└── ...
Concepts cles :
- Log Group : Un groupe par fonction Lambda (
/aws/lambda/nom-fonction) - Log Stream : Un flux par instance de conteneur Lambda
- Log Event : Chaque ligne de log individuelle
Format des Logs Lambda
Message START
START RequestId: 12345-abcde-67890 Version: $LATEST
Messages personnalises (votre code)
# Python
print("Traitement de l'utilisateur:", user_id)
logger.info("Connexion a la base de donnees")
logger.error("Erreur: fichier non trouve")
// Node.js
console.log("Traitement de l'utilisateur:", userId);
console.info("Connexion a la base de donnees");
console.error("Erreur: fichier non trouve");
Message END
END RequestId: 12345-abcde-67890
Message REPORT (tres important!)
REPORT RequestId: 12345-abcde-67890
Duration: 234.56 ms
Billed Duration: 235 ms
Memory Size: 128 MB
Max Memory Used: 67 MB
Init Duration: 145.23 ms
Analyse du REPORT
┌─────────────────────────────────────────────────────────────────┐
│ ANALYSE DU REPORT │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Duration: 234.56 ms │
│ └── Temps reel d'execution de votre code │
│ │
│ Billed Duration: 235 ms │
│ └── Temps facture (arrondi au ms superieur) │
│ │
│ Memory Size: 128 MB │
│ └── Memoire ALLOUEE (configuree) │
│ │
│ Max Memory Used: 67 MB │
│ └── Memoire REELLEMENT utilisee │
│ Si proche de Memory Size = risque OOM! │
│ │
│ Init Duration: 145.23 ms (Cold Start seulement) │
│ └── Temps d'initialisation du conteneur │
│ │
└─────────────────────────────────────────────────────────────────┘
Bonnes Pratiques de Logging
1. Logging Structure (JSON)
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
# Log structure pour faciliter l'analyse
log_entry = {
"level": "INFO",
"request_id": context.aws_request_id,
"action": "process_order",
"order_id": event.get("order_id"),
"user_id": event.get("user_id")
}
logger.info(json.dumps(log_entry))
2. Niveaux de Log
┌─────────────────────────────────────────────────────────────────┐
│ NIVEAUX DE LOG │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DEBUG → Details techniques (dev seulement) │
│ INFO → Operations normales │
│ WARNING → Situations anormales mais gerees │
│ ERROR → Erreurs qui necessitent attention │
│ CRITICAL → Erreurs graves, fonction compromise │
│ │
│ Production : INFO et plus │
│ Developpement : DEBUG et plus │
│ │
└─────────────────────────────────────────────────────────────────┘
3. Informations Essentielles a Logger
def lambda_handler(event, context):
# TOUJOURS logger au debut
logger.info(f"START - RequestId: {context.aws_request_id}")
logger.info(f"Event: {json.dumps(event)}")
try:
# Votre logique
result = process_data(event)
# Logger le succes
logger.info(f"SUCCESS - Result: {result}")
return result
except Exception as e:
# Logger l'erreur avec details
logger.error(f"ERROR - Type: {type(e).__name__}")
logger.error(f"ERROR - Message: {str(e)}")
logger.error(f"ERROR - Event: {json.dumps(event)}")
raise
Recherche dans les Logs
CloudWatch Logs Insights
-- Trouver toutes les erreurs
fields @timestamp, @message
| filter @message like /ERROR/
| sort @timestamp desc
| limit 100
-- Analyser les durees d'execution
fields @timestamp, @duration
| filter @type = "REPORT"
| stats avg(@duration), max(@duration), min(@duration)
-- Trouver les Cold Starts
fields @timestamp, @message
| filter @message like /Init Duration/
| sort @timestamp desc
-- Memoire proche de la limite
fields @timestamp, @maxMemoryUsed, @memorySize
| filter @type = "REPORT"
| filter @maxMemoryUsed / @memorySize > 0.8
Filtres de Patterns
# Trouver les erreurs
?ERROR ?Error ?error
# Trouver un RequestId specifique
"12345-abcde-67890"
# Trouver les timeouts
"Task timed out"
# Trouver les OOM (Out of Memory)
"Runtime exited" "memory"
Retention des Logs
┌─────────────────────────────────────────────────────────────────┐
│ RETENTION DES LOGS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Par defaut : Les logs sont conserves INDEFINIMENT │
│ └── Attention aux couts de stockage! │
│ │
│ Options de retention : │
│ • 1 jour, 3 jours, 5 jours, 1 semaine │
│ • 2 semaines, 1 mois, 2 mois, 3 mois │
│ • 6 mois, 1 an, 13 mois, 18 mois │
│ • 2 ans, 3 ans, 5 ans, 10 ans │
│ • Jamais expirer │
│ │
│ Recommandation : │
│ • Dev/Test : 1-7 jours │
│ • Production : 30-90 jours │
│ • Compliance : selon reglementation │
│ │
└─────────────────────────────────────────────────────────────────┘
Metriques Importantes
| Metrique | Description | Seuil d'alerte typique |
|---|---|---|
| Invocations | Nombre d'appels | Selon baseline |
| Duration | Temps d'execution | > 80% du timeout |
| Errors | Nombre d'erreurs | > 1% des invocations |
| Throttles | Invocations limitees | > 0 |
| ConcurrentExecutions | Executions paralleles | > 80% de la limite |
Exercice Pratique
Scenario : Analyser les logs d'une fonction problematique
Logs observes :
────────────────────────────────────────────────────────
START RequestId: abc-123
Connecting to database...
REPORT Duration: 29543.21 ms Billed: 29544 ms
Memory: 128 MB Max Used: 125 MB
START RequestId: def-456
Connecting to database...
Task timed out after 30.00 seconds
START RequestId: ghi-789
Runtime exited with error: signal: killed
────────────────────────────────────────────────────────
Questions :
1. Quel est le probleme principal ?
2. Quelles metriques sont anormales ?
3. Quelles solutions proposez-vous ?
Voir l'analyse
Problemes identifies :
- Timeout : La fonction prend presque 30 secondes (limite)
- Memoire : 125/128 MB utilises (97% - critique!)
- OOM : "Runtime exited... signal: killed" = Out of Memory
Solutions :
- Augmenter la memoire (256 MB ou plus)
- Optimiser le code de connexion BDD (connection pooling)
- Augmenter le timeout si necessaire
- Ajouter des logs pour identifier le goulot d'etranglement
Resume
- CloudWatch Logs capture automatiquement tous les logs Lambda
- Le message REPORT contient les metriques de performance
- Utilisez le logging structure (JSON) pour faciliter l'analyse
- Configurez la retention pour controler les couts
- CloudWatch Logs Insights permet des requetes SQL sur les logs
Prochaine section : Quiz de Validation