Aller au contenu principal

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​

MetriqueDescriptionSeuil d'alerte typique
InvocationsNombre d'appelsSelon baseline
DurationTemps d'execution> 80% du timeout
ErrorsNombre d'erreurs> 1% des invocations
ThrottlesInvocations limitees> 0
ConcurrentExecutionsExecutions 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 :

  1. Timeout : La fonction prend presque 30 secondes (limite)
  2. Memoire : 125/128 MB utilises (97% - critique!)
  3. OOM : "Runtime exited... signal: killed" = Out of Memory

Solutions :

  1. Augmenter la memoire (256 MB ou plus)
  2. Optimiser le code de connexion BDD (connection pooling)
  3. Augmenter le timeout si necessaire
  4. 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