Use Cases

Claude Code × AWS CloudWatch Guía Completa | Análisis de Logs, Alarmas y Dashboards Automáticos

Optimiza AWS CloudWatch con Claude Code. Código práctico para análisis de patrones de logs, configuración automática de alarmas, dashboards de métricas e investigación de incidentes.

“¡Hay un error en producción! Pero hay demasiados logs y no sé por dónde empezar.” — Es el pánico clásico durante la gestión de incidentes.

CloudWatch es el servicio de monitoreo estándar de AWS, pero con volúmenes enormes de logs, la información crítica queda enterrada y la configuración de alarmas suele posponerse. En mi trabajo monitoreo un sistema con ECS + Lambda, y dejar que Claude Code lea los logs para identificar la causa ha reducido el tiempo promedio de respuesta a incidentes en un 40%.

Este artículo explica paso a paso cómo automatizar el análisis de logs de CloudWatch, el diseño de alarmas y la construcción de dashboards con Claude Code.


Componentes principales de CloudWatch

CloudWatch Logs      : Almacenamiento y búsqueda de logs de apps y servicios AWS
CloudWatch Metrics   : Datos numéricos como uso de CPU y conteo de solicitudes
CloudWatch Alarms    : Detecta umbrales superados en métricas y notifica a SNS, etc.
CloudWatch Dashboards: Vistas personalizadas para visualizar métricas y logs
Log Insights         : Motor de consultas similar a SQL para analizar logs

Paso 1: Delegar el análisis de patrones de logs a Claude Code

Durante un incidente, lo primero es entender el patrón de los logs de error.

# Obtener logs de error de la última hora
aws logs filter-log-events \
  --log-group-name "/ecs/myapp" \
  --start-time $(date -d "1 hour ago" +%s000) \
  --filter-pattern "ERROR" \
  --output json > error-logs.json

claude -p "
Analiza los siguientes logs de error de CloudWatch y:

1. Clasifica los errores por tipo (5xx, 4xx, errores de conexión a BD, timeouts, etc.)
2. Identifica el error más frecuente
3. Determina el momento en que los errores se dispararon
4. Propón hipótesis sobre la causa raíz
5. Sugiere los próximos pasos de investigación

$(cat error-logs.json | head -500)
"

Generar automáticamente consultas de Log Insights

claude -p "
Genera consultas de CloudWatch Log Insights para los siguientes propósitos:

1. Tasa de error por endpoint en la última hora (top 10)
2. Detalles de solicitudes con latencia superior a 500 ms
3. Todos los logs de operaciones de un usuario específico (user_id: 12345)
4. Primeros errores ocurridos dentro de los 30 minutos tras un despliegue

Formato de log: JSON (timestamp, level, message, user_id, endpoint, duration_ms, status_code)
"

Ejemplo de consultas de Log Insights generadas:

-- Tasa de error por endpoint
fields @timestamp, endpoint, status_code
| filter status_code >= 400
| stats count() as error_count by endpoint
| sort error_count desc
| limit 10

-- Solicitudes con latencia superior a 500 ms
fields @timestamp, endpoint, duration_ms, user_id
| filter duration_ms > 500
| sort duration_ms desc
| limit 50

-- Logs de operaciones de un usuario específico
fields @timestamp, level, message, endpoint
| filter user_id = "12345"
| sort @timestamp desc
| limit 100

Paso 2: Generar automáticamente la configuración de alarmas

claude -p "
Diseña todas las alarmas de CloudWatch necesarias para el siguiente sistema.
Implementa en CDK TypeScript.

[Arquitectura del sistema]
- ECS Fargate (servidor API, 2–10 instancias)
- RDS PostgreSQL
- ALB (Application Load Balancer)
- Lambda (procesamiento por lotes)

[Requisitos de alarmas]
- Producción: alarmas que se activen en menos de 5 minutos
- Destinos de notificación: SNS → Slack y PagerDuty
- Alarmas de dos niveles (Warning / Critical)
- Fuera del horario laboral: solo Critical
"
// lib/monitoring-stack.ts
import * as cdk from "aws-cdk-lib";
import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch";
import * as actions from "aws-cdk-lib/aws-cloudwatch-actions";
import * as sns from "aws-cdk-lib/aws-sns";

export class MonitoringStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const alertTopic = sns.Topic.fromTopicArn(
      this, "AlertTopic",
      `arn:aws:sns:${this.region}:${this.account}:prod-alerts`
    );
    const warnTopic = sns.Topic.fromTopicArn(
      this, "WarnTopic",
      `arn:aws:sns:${this.region}:${this.account}:prod-warnings`
    );

    // Alarma de tasa de error 5xx de ALB
    const alb5xxAlarm = new cloudwatch.Alarm(this, "Alb5xxAlarm", {
      alarmName: "prod-alb-5xx-critical",
      alarmDescription: "Tasa de error 5xx de ALB superó el 5%",
      metric: new cloudwatch.Metric({
        namespace: "AWS/ApplicationELB",
        metricName: "HTTPCode_Target_5XX_Count",
        dimensionsMap: { LoadBalancer: "app/myapp/xxx" },
        statistic: "Sum",
        period: cdk.Duration.minutes(5),
      }),
      threshold: 10,
      evaluationPeriods: 2,
      comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
      treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
    });
    alb5xxAlarm.addAlarmAction(new actions.SnsAction(alertTopic));

    // Alarma de uso de CPU de ECS (Warning/Critical)
    const ecsCpuWarning = new cloudwatch.Alarm(this, "EcsCpuWarning", {
      alarmName: "prod-ecs-cpu-warning",
      metric: new cloudwatch.Metric({
        namespace: "AWS/ECS",
        metricName: "CPUUtilization",
        dimensionsMap: { ClusterName: "myapp-cluster", ServiceName: "myapp-service" },
        statistic: "Average",
        period: cdk.Duration.minutes(5),
      }),
      threshold: 70,
      evaluationPeriods: 3,
    });
    ecsCpuWarning.addAlarmAction(new actions.SnsAction(warnTopic));

    const ecsCpuCritical = new cloudwatch.Alarm(this, "EcsCpuCritical", {
      alarmName: "prod-ecs-cpu-critical",
      metric: new cloudwatch.Metric({
        namespace: "AWS/ECS",
        metricName: "CPUUtilization",
        dimensionsMap: { ClusterName: "myapp-cluster", ServiceName: "myapp-service" },
        statistic: "Average",
        period: cdk.Duration.minutes(5),
      }),
      threshold: 90,
      evaluationPeriods: 2,
    });
    ecsCpuCritical.addAlarmAction(new actions.SnsAction(alertTopic));

    // Alarma de número de conexiones de RDS
    const rdsConnectionAlarm = new cloudwatch.Alarm(this, "RdsConnectionAlarm", {
      alarmName: "prod-rds-connections-critical",
      metric: new cloudwatch.Metric({
        namespace: "AWS/RDS",
        metricName: "DatabaseConnections",
        dimensionsMap: { DBInstanceIdentifier: "myapp-db" },
        statistic: "Maximum",
        period: cdk.Duration.minutes(5),
      }),
      threshold: 80,  // 80% del máximo de conexiones de db.t3.micro
      evaluationPeriods: 2,
    });
    rdsConnectionAlarm.addAlarmAction(new actions.SnsAction(alertTopic));

    // Alarma de errores de Lambda
    const lambdaErrorAlarm = new cloudwatch.Alarm(this, "LambdaErrorAlarm", {
      alarmName: "prod-lambda-errors-critical",
      metric: new cloudwatch.Metric({
        namespace: "AWS/Lambda",
        metricName: "Errors",
        dimensionsMap: { FunctionName: "myapp-batch" },
        statistic: "Sum",
        period: cdk.Duration.minutes(15),
      }),
      threshold: 5,
      evaluationPeriods: 1,
    });
    lambdaErrorAlarm.addAlarmAction(new actions.SnsAction(alertTopic));
  }
}

Paso 3: Generar automáticamente un dashboard personalizado

claude -p "
Genera un dashboard de CloudWatch en CDK que muestre la siguiente información.

[Diseño del dashboard]
Fila 1: Estado general del sistema (solicitudes ALB, tasa 5xx, latencia P50/P95/P99)
Fila 2: Servicio ECS (CPU, memoria, número de tareas en ejecución)
Fila 3: RDS (conexiones, latencia, uso de CPU)
Fila 4: Lambda (invocaciones, errores, duración)
Fila 5: Métricas de negocio (nuevos registros, tasa de éxito de pagos) ← métricas personalizadas
"
// Definición del dashboard (fragmento)
const dashboard = new cloudwatch.Dashboard(this, "AppDashboard", {
  dashboardName: "myapp-production",
});

dashboard.addWidgets(
  new cloudwatch.Row(
    new cloudwatch.GraphWidget({
      title: "Solicitudes ALB",
      left: [new cloudwatch.Metric({
        namespace: "AWS/ApplicationELB",
        metricName: "RequestCount",
        statistic: "Sum",
        period: cdk.Duration.minutes(1),
      })],
      width: 8,
    }),
    new cloudwatch.GraphWidget({
      title: "Tasa de error 5xx de ALB (%)",
      left: [new cloudwatch.MathExpression({
        expression: "5xx / (2xx + 3xx + 4xx + 5xx) * 100",
        usingMetrics: {
          "5xx": new cloudwatch.Metric({ metricName: "HTTPCode_Target_5XX_Count", namespace: "AWS/ApplicationELB", statistic: "Sum" }),
          "2xx": new cloudwatch.Metric({ metricName: "HTTPCode_Target_2XX_Count", namespace: "AWS/ApplicationELB", statistic: "Sum" }),
          "3xx": new cloudwatch.Metric({ metricName: "HTTPCode_Target_3XX_Count", namespace: "AWS/ApplicationELB", statistic: "Sum" }),
          "4xx": new cloudwatch.Metric({ metricName: "HTTPCode_Target_4XX_Count", namespace: "AWS/ApplicationELB", statistic: "Sum" }),
        },
        period: cdk.Duration.minutes(1),
      })],
      width: 8,
    }),
  )
);

Paso 4: Delegar la investigación de incidentes a Claude Code

claude -p "
Quiero investigar un incidente en producción. Ejecuta los siguientes comandos y analiza los resultados:

1. aws logs filter-log-events --log-group-name '/ecs/myapp' \
   --start-time \$(date -d '2 hours ago' +%s000) \
   --filter-pattern 'ERROR' --limit 100

2. aws cloudwatch get-metric-statistics \
   --namespace AWS/ApplicationELB \
   --metric-name HTTPCode_Target_5XX_Count \
   --start-time \$(date -d '2 hours ago' -u +%Y-%m-%dT%H:%M:%SZ) \
   --end-time \$(date -u +%Y-%m-%dT%H:%M:%SZ) \
   --period 300 --statistics Sum

Basándote en los resultados, resume:
- Hora de inicio del incidente
- Número estimado de usuarios afectados
- Top 3 hipótesis sobre la causa raíz
- Acciones de respuesta inmediata
"

Paso 5: Diseñar automáticamente métricas personalizadas

claude -p "
Genera código Node.js (AWS SDK v3) para medir los siguientes KPIs de negocio
de un e-commerce como métricas personalizadas de CloudWatch.

Métricas a medir:
- Número de pagos exitosos y fallidos (cada minuto)
- Tasa de abandono de carrito (cada 5 minutos)
- Nuevos registros de miembros (cada hora)

Espacio de nombres: MyApp/Business
Etiquetar cada métrica con el entorno (Production/Staging)
"
// src/monitoring/business-metrics.ts
import { CloudWatchClient, PutMetricDataCommand } from "@aws-sdk/client-cloudwatch";

const cw = new CloudWatchClient({ region: process.env.AWS_REGION });
const NAMESPACE = "MyApp/Business";
const ENV = process.env.NODE_ENV ?? "development";

export async function recordPaymentSuccess() {
  await cw.send(new PutMetricDataCommand({
    Namespace: NAMESPACE,
    MetricData: [{
      MetricName: "PaymentSuccess",
      Value: 1,
      Unit: "Count",
      Dimensions: [{ Name: "Environment", Value: ENV }],
    }],
  }));
}

export async function recordPaymentFailure(reason: string) {
  await cw.send(new PutMetricDataCommand({
    Namespace: NAMESPACE,
    MetricData: [{
      MetricName: "PaymentFailure",
      Value: 1,
      Unit: "Count",
      Dimensions: [
        { Name: "Environment", Value: ENV },
        { Name: "Reason", Value: reason },
      ],
    }],
  }));
}

4 errores comunes a evitar

1. evaluationPeriods demasiado corto

// ❌ La alarma se activa con picos momentáneos
evaluationPeriods: 1,
threshold: 10,

// ✅ La alarma solo se activa tras 3 períodos consecutivos (reduce falsos positivos)
evaluationPeriods: 3,
threshold: 10,
datapointsToAlarm: 2,  // Alarma cuando el umbral se supera en 2 de 3 períodos

2. Ignorar los costos de Log Insights

Log Insights cobra según la cantidad de datos escaneados. Ejecutar consultas sin limitar el rango de tiempo puede generar facturas inesperadas. Especifica siempre --start-time y --end-time.

3. Las métricas personalizadas de alta resolución son costosas

Las métricas estándar (60 segundos) son gratuitas, pero las de alta resolución (1 segundo) cuestan aproximadamente 10 veces más. La agregación de 1 minuto suele ser suficiente para métricas de negocio.

4. No configurar el período de retención de logs de Lambda

El valor predeterminado es “Sin expiración”, lo que hace que los costos de almacenamiento crezcan indefinidamente. Siempre configura un período de retención en los grupos de logs.

new logs.LogGroup(this, "AppLogGroup", {
  logGroupName: "/ecs/myapp",
  retention: logs.RetentionDays.ONE_MONTH,  // Eliminación automática tras 30 días
});

Resumen

TareaContribución de Claude Code
Análisis de logsLee logs de error y propone hipótesis de causa raíz con pasos de solución
Consultas Log InsightsGenera consultas a partir de una descripción del objetivo de análisis
Configuración de alarmasGenera código CDK en bloque a partir de una descripción del sistema
DashboardGenera definiciones de widgets a partir de una descripción de lo que quieres ver
Investigación de incidentesEjecuta comandos AWS CLI y analiza los resultados

“Configuraremos el monitoreo más tarde” — y entonces llega un incidente y no tienes visibilidad. Con Claude Code puedes tener alarmas y dashboards de nivel producción listos en 30 minutos.

Artículos relacionados

Referencias

#claude-code #aws #cloudwatch #monitoring #observability #devops

Lleva tu flujo con Claude Code al siguiente nivel

50 plantillas de prompts probadas en producción, listas para copiar y pegar en Claude Code.

Gratis

PDF gratuito: Hoja de trucos de Claude Code en 5 minutos

Solo deja tu correo y te enviaremos al instante la hoja de trucos en una página A4.

Cuidamos tus datos personales y nunca enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero apasionado por Claude Code. Dirige claudecode-lab.com, un medio tecnológico en 10 idiomas con más de 2.000 páginas.