AWS CloudWatch Investigation

Par github · awesome-copilot

Modèles d'investigation réutilisables pour AWS CloudWatch : templates de requêtes Logs Insights, corrélation alarme-déploiement, arbre de décision de réduction du rayon de blast, et patterns de requêtes de métriques style PromQL pour le triage structuré d'incidents.

npx skills add https://github.com/github/awesome-copilot --skill AWS CloudWatch Investigation

Skill d'Investigation AWS CloudWatch

Patterns réutilisables pour investiguer les incidents de production avec CloudWatch Logs, Metrics et Alarms. Ces patterns sont conçus pour être composés ensemble lors du triage d'incident.


Pattern 1 : Modèles de requête Logs Insights

Détection de pic d'erreurs

Trouver les erreurs les plus fréquentes dans une fenêtre de temps, groupées par type d'erreur :

fields @timestamp, @message, @logStream
| filter @message like /(?i)(error|exception|fatal|critical)/
| stats count(*) as errorCount by bin(5m), @logStream
| sort errorCount desc
| limit 20

Répartition de la latence P99 par opération

Identifier quelles opérations génèrent les pics de latence :

fields @timestamp, @duration, operation
| filter ispresent(@duration)
| stats avg(@duration) as avgMs,
        pct(@duration, 50) as p50Ms,
        pct(@duration, 95) as p95Ms,
        pct(@duration, 99) as p99Ms,
        count(*) as invocations
  by operation
| sort p99Ms desc
| limit 15

Détection de démarrage à froid Lambda

Quantifier l'impact des démarrages à froid pendant un incident :

fields @timestamp, @duration, @initDuration, @memorySize, @maxMemoryUsed
| filter ispresent(@initDuration)
| stats count(*) as coldStarts,
        avg(@initDuration) as avgInitMs,
        max(@initDuration) as maxInitMs,
        avg(@duration) as avgDurationMs
  by bin(5m)
| sort @timestamp desc

Détection de dépassement mémoire (OOM)

Trouver les fonctions Lambda ou conteneurs arrêtés par manque de mémoire :

fields @timestamp, @message, @logStream, @memorySize, @maxMemoryUsed
| filter @message like /Runtime exited|out of memory|OOMKilled|Cannot allocate memory|MemoryError/
| stats count(*) as oomEvents by @logStream, bin(10m)
| sort oomEvents desc
| limit 10

Pour la tendance d'utilisation mémoire avant OOM :

fields @timestamp, @maxMemoryUsed, @memorySize
| filter ispresent(@maxMemoryUsed)
| stats max(@maxMemoryUsed / @memorySize * 100) as peakMemPct,
        avg(@maxMemoryUsed / @memorySize * 100) as avgMemPct
  by bin(5m)
| sort @timestamp desc

Détection de délai d'expiration

Trouver les invocations qui ont atteint le timeout configuré :

fields @timestamp, @duration, @logStream, @requestId
| filter @message like /Task timed out/ or @duration > 28000
| stats count(*) as timeouts by @logStream, bin(5m)
| sort timeouts desc

Pattern 2 : Corrélation entre l'historique des alarmes et les événements de déploiement

Processus

  1. Récupérer l'heure de transition de l'alarme — noter le timestamp exact quand l'alarme est entrée en état ALARM.
  2. Interroger CloudTrail pour les événements liés aux déploiements dans la fenêtre [alarm_time - 30min, alarm_time] :
# Requête CloudTrail Lake pour les événements de déploiement
SELECT eventTime, eventName, userIdentity.arn, requestParameters
FROM <event-data-store-id>
WHERE eventTime > '<alarm_time_minus_30m>'
  AND eventTime < '<alarm_time>'
  AND eventName IN (
    'UpdateFunctionCode', 'UpdateFunctionConfiguration',
    'UpdateService', 'CreateDeployment', 'RegisterTaskDefinition',
    'CreateChangeSet', 'ExecuteChangeSet',
    'StartPipelineExecution', 'PutImage'
  )
ORDER BY eventTime DESC
  1. Critères de corrélation — un déploiement est « corrélé » si :

    • Il cible le même service/resource que l'alarme
    • Il s'est complété dans les 15 minutes avant la transition de l'alarme
    • L'identité du déployeur correspond à un rôle CI/CD (pas un humain appliquant un hotfix)
  2. Renforcer la corrélation :

    • Vérifier si la même alarme était saine dans le cycle de déploiement précédent
    • Confirmer qu'il n'y a pas d'autres changements environnementaux (événements de scaling, changements de config) dans la même fenêtre
    • Chercher les défaillances de canary/moniteurs synthétiques commencées au même moment

Format de sortie

Deploy Correlation:
  Event: UpdateFunctionCode
  Time: 2024-03-15T14:23:07Z (12 min avant l'alarme)
  Actor: arn:aws:sts::123456789012:assumed-role/github-actions-deploy/session
  Resource: arn:aws:lambda:us-east-1:123456789012:function:payment-processor
  Correlation: STRONG — même resource, acteur CI/CD, alarme OK cycle précédent

Pattern 3 : Arbre de décision pour réduire le rayon d'impact

Utiliser cet arbre pour délimiter systématiquement un incident du plus large au plus spécifique :

START
  |
  v
[1] ACCOUNT — Quel(s) compte(s) montrent l'alarme ?
  |  - Vérifier : les alarmes se déclenchent-elles sur plusieurs comptes ?
  |  - Si oui → suspecter un service partagé (SSO, réseau, pipeline de déploiement partagé)
  |  - Si non → procéder à la Région
  v
[2] REGION — Quelle(s) région(s) sont affectées ?
  |  - Vérifier : même alarme dans d'autres régions ?
  |  - Si multi-région → suspecter un service global (IAM, Route53, S3 global)
  |  - Si single-région → procéder au Service
  v
[3] SERVICE — Quel namespace de service montre une dégradation ?
  |  - Vérifier le namespace CloudWatch : AWS/Lambda, AWS/ECS, AWS/ApiGateway, etc.
  |  - Si plusieurs services → suspecter une dépendance partagée (VPC, NAT, DNS, IAM)
  |  - Si service unique → procéder à l'Opération
  v
[4] OPERATION — Quelle action API ou fonction échoue ?
  |  - Pour Lambda : quel nom de fonction ?
  |  - Pour ECS : quel service/définition de task ?
  |  - Pour API GW : quel stage/resource/method ?
  |  - Si toutes les opérations → suspecter un problème au niveau du service (throttling, quota)
  |  - Si opération spécifique → procéder à la Resource
  v
[5] RESOURCE — Quelle instance de resource spécifique ?
     - Function ARN, Task ID, identifiant DB instance
     - C'est votre cible d'investigation
     - Procéder à l'analyse des logs et traces limitée à cette resource

Investigation de dépendance partagée

Quand le rayon d'impact s'étend sur plusieurs services, investiguer dans cet ordre :

  1. VPC/Réseau — NAT Gateway ErrorPortAllocation, pertes de paquets, défaillances de résolution DNS
  2. IAM/STS — ThrottlingException sur AssumeRole, latence de vente de tokens
  3. Dépendance aval — base de données partagée, cache ou API externe
  4. Pipeline de déploiement — déploiements simultanés entre services depuis le même pipeline run
  5. Événement AWS — vérifier AWS Health Dashboard et Service Health pour la région

Pattern 4 : Patterns de requête métrique de style PromQL

Ces patterns utilisent les maths de métrique CloudWatch et GetMetricData pour construire des signaux composites. Les exprimer comme des requêtes de métrique pour les dashboards ou la récupération programmatique.

Taux d'erreur en pourcentage

MetricDataQueries:
  - Id: errors
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Errors
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 60
      Stat: Sum
  - Id: invocations
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Invocations
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 60
      Stat: Sum
  - Id: error_rate
    Expression: "errors / invocations * 100"
    Label: "Error Rate %"

Détection d'anomalie de latence (Comparaison à la baseline)

MetricDataQueries:
  - Id: current_p99
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Duration
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 300
      Stat: p99
  - Id: baseline_p99
    MetricStat:
      Metric:
        Namespace: AWS/Lambda
        MetricName: Duration
        Dimensions: [{Name: FunctionName, Value: TARGET}]
      Period: 300
      Stat: p99
    # Utiliser StartTime/EndTime sur la même fenêtre la semaine précédente
  - Id: anomaly_ratio
    Expression: "current_p99 / baseline_p99"
    Label: "Latency vs Baseline (ratio > 2 = anomaly)"

Score de pression de throttling

Combiner plusieurs signaux de throttling en une seule métrique de pression :

MetricDataQueries:
  - Id: lambda_throttles
    MetricStat:
      Metric: {Namespace: AWS/Lambda, MetricName: Throttles}
      Period: 60
      Stat: Sum
  - Id: api_gw_429s
    MetricStat:
      Metric: {Namespace: AWS/ApiGateway, MetricName: 4XXError, Dimensions: [{Name: ApiName, Value: TARGET}]}
      Period: 60
      Stat: Sum
  - Id: dynamo_throttles
    MetricStat:
      Metric: {Namespace: AWS/DynamoDB, MetricName: ThrottledRequests, Dimensions: [{Name: TableName, Value: TARGET}]}
      Period: 60
      Stat: Sum
  - Id: throttle_pressure
    Expression: "lambda_throttles + api_gw_429s + dynamo_throttles"
    Label: "Combined Throttle Pressure"

Marge disponible d'exécution concurrente

MetricDataQueries:
  - Id: concurrent
    MetricStat:
      Metric: {Namespace: AWS/Lambda, MetricName: ConcurrentExecutions}
      Period: 60
      Stat: Maximum
  - Id: headroom
    Expression: "1000 - concurrent"
    Label: "Remaining Concurrency (account limit 1000)"

Pattern 5 : Reconstruction de chronologie d'incident

Processus

Reconstituer une chronologie précise en fusionnant les données de plusieurs sources :

  1. Collecter les timestamps :
Source Requête Rendement
CloudWatch Alarms API d'historique des alarmes Heures de transition d'état
CloudWatch Metrics GetMetricData avec période 1-min Premier point d'anomalie
CloudWatch Logs Logs Insights avec earliest(@timestamp) Première occurrence d'erreur
CloudTrail LookupEvents filtrée par heure Événements de déploiement/changement
AWS Health DescribeEvents Incidents côté AWS
  1. Construire la chronologie :
fields @timestamp, @message
| filter @message like /ERROR|WARN|timeout|refused|denied/
| stats earliest(@timestamp) as firstSeen, latest(@timestamp) as lastSeen, count(*) as occurrences
  by @message
| sort firstSeen asc
| limit 20
  1. Identifier la séquence :
Timeline:
  T-15m: CloudTrail — UpdateFunctionCode par rôle CI/CD
  T-12m: Logs — première erreur "Connection refused to payments-api.internal"
  T-10m: Metrics — nombre d'erreurs franchit le seuil 5/min
  T-8m:  Alarm — PaymentProcessorErrors entre en état ALARM
  T-5m:  Metrics — latence p99 monte à 28s (timeout)
  T-0:   Actuel — taux d'erreur 45%, alarme toujours déclenchée
  1. Déterminer l'événement racine — le changement le plus ancien qui a précédé tous les symptômes. Remonter depuis le premier symptôme jusqu'à la mutation la plus récente (déploiement, changement de config, événement de scaling ou décalage de dépendance externe).

Pièges

  • Les timestamps des métriques CloudWatch sont fin-de-période. Un datapoint 1-minute à 14:05 couvre 14:04-14:05.
  • Les événements CloudTrail peuvent avoir jusqu'à 15 minutes de délai de livraison. Utiliser eventTime, pas l'heure d'ingestion.
  • Les timestamps du log group dépendent de l'intervalle de flush de l'agent/SDK. Prévoir 30-60s de décalage horaire.
  • Les changements d'état d'alarme ont un délai d'évaluation intégré (périodes x périodes d'évaluation). L'anomalie réelle a commencé plus tôt.

Skills similaires