Sessão 038 — CloudWatch: Composite Alarms, anomaly detection e automated actions
Dependências: session-037-cloudwatch-logs-insights-queries
Objetivo
Ao final desta sessão, você conseguirá criar um Composite Alarm que só dispara quando erros e alta latência ocorrem simultaneamente (reduzindo falsos positivos), habilitar anomaly detection em uma métrica e ajustar a banda de tolerância, configurar alarm actions que invocam Lambda ou SSM Automation (além de SNS), e entender os estados de alarm e a semântica de MISSING_DATA.
Contexto
[FATO] Um alarm CloudWatch padrão monitora uma única métrica com um threshold fixo. Dois recursos avançados estendem isso: Composite Alarms combinam múltiplos alarms via expressões lógicas (AND, OR, NOT), e Anomaly Detection substitui o threshold fixo por uma banda dinâmica calculada por ML com base no histórico da métrica.
[CONSENSO] A principal motivação para Composite Alarms em produção é reduzir falsos positivos: um spike de latência às 3h da manhã sem aumento de erros raramente exige acordar alguém. Composite Alarms permitem modelar esse raciocínio: ALARM(HighLatency) AND ALARM(HighErrorRate) — só dispara se ambos forem verdadeiros simultaneamente.
Conceitos principais
1. Estados de alarm e semântica de avaliação
[FATO] Todo alarm CloudWatch (simples ou composto) pode estar em um de três estados:
Estado Significado
────────────────────────────────────────────────────────────────
OK Métrica está dentro do threshold / banda
ALARM Métrica violou o threshold / banda
INSUFFICIENT_DATA Dados insuficientes para avaliar
(comum em alarmes recém-criados ou métricas
com low-cardinality de dados)
[FATO] O parâmetro Datapoints to alarm (M out of N) controla a sensibilidade:
M de N — exemplo: 3 de 5
┌─────────────────────────────────────────────────────┐
│ Evaluation periods (N): 5 │
│ Datapoints to alarm (M): 3 │
│ │
│ Alarme só dispara se 3 dos últimos 5 pontos │
│ violarem o threshold — reduz falsos positivos │
│ em métricas ruidosas │
└─────────────────────────────────────────────────────┘
M = N (ex: 3 de 3): N períodos consecutivos violando → alarme dispara
M < N (ex: 2 de 5): menos sensível a outliers isolados
[FATO] Missing data treatment — comportamento quando pontos de dados estão ausentes:
Valor Comportamento
────────────────────────────────────────────────────────────────
notBreaching Ausência = OK (dados faltando são normais)
breaching Ausência = ALARM (ex: heartbeat — ausência é falha)
ignore Mantém estado atual do alarm
missing Alarm vai para INSUFFICIENT_DATA
2. Composite Alarms: rule expression
[FATO] Um Composite Alarm avalia uma AlarmRule — expressão booleana sobre os estados de outros alarms. Suporta ALARM(), OK(), INSUFFICIENT_DATA() como funções de estado, e AND, OR, NOT, parênteses como operadores lógicos.
Exemplos de AlarmRule:
-- Dispara apenas se AMBAS as condições estiverem em ALARM
ALARM("payment-high-error-rate") AND ALARM("payment-high-latency")
-- Dispara se qualquer uma estiver em ALARM
ALARM("payment-high-error-rate") OR ALARM("payment-high-latency")
-- Dispara para erros de backend, a menos que manutenção esteja programada
ALARM("payment-high-error-rate") AND NOT ALARM("maintenance-window-active")
-- Expressão complexa com parênteses
(ALARM("payment-high-error-rate") OR ALARM("payment-high-latency"))
AND NOT OK("health-check-endpoint")
-- Composite pode referenciar outros Composite Alarms
ALARM("payment-composite") AND ALARM("database-composite")
[FATO] Composite Alarms têm custo: $0.50/alarm/mês (us-east-1, além do custo dos alarms filhos).
[FATO] Composite Alarms não avaliam métricas diretamente — eles apenas agregam estados de outros alarms. A expressão ALARM("alarm-name") verifica se o alarm nomeado está no estado ALARM.
[FATO] Ciclos de dependência: dois Composite Alarms dependendo um do outro param de ser avaliados. Para quebrar o ciclo, mude o AlarmRule de um deles para FALSE.
3. Anomaly Detection: banda dinâmica por ML
[FATO] Anomaly Detection analisa o histórico de uma métrica e cria um modelo de valores esperados, considerando padrões horárias, diários e semanais. O resultado é uma banda (lower/upper bound) ao redor dos valores esperados.
Métrica: RequestLatency (ms)
┌─ threshold fixo (rígido)
─── ─── ─── ─── ─── ─── ─── ─── ─── ┤
│
╭─────────────────────────────╮ ← banda superior (normal)
│ valores esperados │
───┤ (ML model) ├─── ← valores esperados
│ │
╰─────────────────────────────╯ ← banda inferior (normal)
Fim de semana: banda mais larga (tráfego mais variável)
Horário comercial: banda mais estreita (padrão mais consistente)
[FATO] O parâmetro Anomaly Detection Threshold (número positivo, não precisa ser inteiro) controla a largura da banda:
- Threshold = 1: banda estreita, mais sensível a desvios
- Threshold = 2: banda moderada (padrão comum)
- Threshold = 3+: banda larga, mais tolerante
[FATO] O modelo leva até 2 semanas para ser totalmente treinado. Nos primeiros 3 dias, a banda é uma aproximação. Excluir períodos anormais do treinamento (deployments, incidents, feriados) melhora a precisão do modelo.
[FATO] Você pode configurar o alarm para disparar quando a métrica estiver:
- Above the band (útil para detecção de latência anômala alta)
- Below the band (útil para detecção de queda anômala de tráfego)
- Outside the band (qualquer desvio, para cima ou para baixo)
[FATO] Anomaly Detection acumula custo por métrica monitorada: $0.30/mês pela criação do detector (além do custo normal da métrica) — us-east-1.
4. Alarm Actions além de SNS
[FATO] Alarm actions disponíveis por tipo de recurso:
Action Type Trigger States Uso
────────────────────────────────────────────────────────────────
SNS notification ALARM, OK, Fan-out para email, SMS,
INSUFFICIENT_DATA Lambda, SQS, HTTP endpoint
Lambda invocation ALARM, OK, Remediação automatizada,
INSUFFICIENT_DATA enriquecimento de alertas
EC2 action ALARM, OK Stop, Start, Reboot,
(apenas EC2 alarms) Terminate da instância
SSM OpsItem ALARM only Cria item no OpsCenter
para gerenciamento de incidentes
SSM Incident Manager ALARM only Cria incidente no AWS
Incident Manager
Auto Scaling ALARM, OK Scale-out / scale-in
(via ScalingPolicy) (configurado na policy,
não diretamente no alarm)
[FATO] Para invocar Lambda diretamente de um alarm (sem SNS como intermediário): o alarm precisa de permissão para chamar lambda:InvokeFunction. A permissão é concedida automaticamente pelo console; via CDK/CLI, é necessário criar um lambda.Permission explicitamente.
Exemplo prático
Cenário: sistema de pagamentos — alerta composto + remediação automatizada
Arquitetura de observabilidade:
- Alarm 1: HighErrorRate — erros > 5% em 2 de 3 períodos de 1 min
- Alarm 2: HighLatency (Anomaly Detection) — latência fora da banda esperada
- Alarm 3: MaintenanceWindow — alarm manual para suprimir notificações durante manutenção
- Composite Alarm: dispara quando HighErrorRate AND HighLatency AND NOT MaintenanceWindow
- Action: Lambda que enriquece o alerta e cria OpsItem no SSM
CDK Python — Stack completa
from aws_cdk import (
Stack, Duration, RemovalPolicy,
aws_cloudwatch as cw,
aws_cloudwatch_actions as cwa,
aws_lambda as lambda_,
aws_sns as sns,
aws_sns_subscriptions as sns_subs,
aws_iam as iam,
)
from constructs import Construct
class PaymentAlarmsStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs):
super().__init__(scope, construct_id, **kwargs)
# ── Métricas base (emitidas via EMF da sessão 036) ────────────
error_metric = cw.Metric(
namespace="MyApp/Payments",
metric_name="FailedPayments",
dimensions_map={"service": "payment-processor", "environment": "production"},
statistic="Sum",
period=Duration.minutes(1),
)
total_metric = cw.Metric(
namespace="MyApp/Payments",
metric_name="SuccessfulPayments",
dimensions_map={"service": "payment-processor", "environment": "production"},
statistic="Sum",
period=Duration.minutes(1),
)
latency_metric = cw.Metric(
namespace="MyApp/Payments",
metric_name="ProcessingLatency",
dimensions_map={"service": "payment-processor", "environment": "production"},
statistic="p95",
period=Duration.minutes(1),
)
# ── Metric Math: taxa de erro (%) ─────────────────────────────
error_rate_metric = cw.MathExpression(
expression="100 * errors / (errors + successes)",
using_metrics={
"errors": error_metric,
"successes": total_metric,
},
period=Duration.minutes(1),
label="Error Rate (%)",
)
# ── Alarm 1: Alta taxa de erros (threshold fixo) ──────────────
high_error_alarm = cw.Alarm(
self, "HighErrorRateAlarm",
alarm_name="payment-high-error-rate",
alarm_description=(
"Payment error rate > 5% for 2 of 3 consecutive minutes.\n"
"**Runbook:** https://wiki.internal/runbooks/payment-errors"
),
metric=error_rate_metric,
threshold=5.0,
evaluation_periods=3,
datapoints_to_alarm=2, # 2 de 3: tolerante a outliers
comparison_operator=cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
treat_missing_data=cw.TreatMissingData.NOT_BREACHING,
)
# ── Alarm 2: Latência anômala (Anomaly Detection) ─────────────
# CfnAnomalyDetector configura o modelo ML
anomaly_detector = cw.CfnAnomalyDetector(
self, "LatencyAnomalyDetector",
namespace="MyApp/Payments",
metric_name="ProcessingLatency",
stat="p95",
dimensions=[
cw.CfnAnomalyDetector.DimensionProperty(
name="service", value="payment-processor"
),
cw.CfnAnomalyDetector.DimensionProperty(
name="environment", value="production"
),
],
# Exclui janelas de manutenção do treinamento do modelo
# configuration=cw.CfnAnomalyDetector.ConfigurationProperty(
# excluded_time_ranges=[
# cw.CfnAnomalyDetector.RangeProperty(
# start_time="2024-01-01T02:00:00",
# end_time="2024-01-01T04:00:00",
# )
# ]
# ),
)
# Alarm baseado na banda do anomaly detector
high_latency_alarm = cw.CfnAlarm(
self, "HighLatencyAnomalyAlarm",
alarm_name="payment-high-latency-anomaly",
alarm_description=(
"Payment p95 latency is outside the expected band "
"(anomaly detection threshold=2)."
),
metrics=[
cw.CfnAlarm.MetricDataQueryProperty(
id="m1",
metric_stat=cw.CfnAlarm.MetricStatProperty(
metric=cw.CfnAlarm.MetricProperty(
namespace="MyApp/Payments",
metric_name="ProcessingLatency",
dimensions=[
cw.CfnAlarm.DimensionProperty(
name="service", value="payment-processor"
),
cw.CfnAlarm.DimensionProperty(
name="environment", value="production"
),
],
),
stat="p95",
period=60,
),
return_data=True,
),
cw.CfnAlarm.MetricDataQueryProperty(
id="ad1",
expression="ANOMALY_DETECTION_BAND(m1, 2)", # threshold=2
label="Anomaly Band",
return_data=True,
),
],
comparison_operator="GreaterThanUpperThreshold",
threshold_metric_id="ad1",
evaluation_periods=3,
datapoints_to_alarm=2,
treat_missing_data="notBreaching",
)
# ── Alarm 3: Janela de manutenção (controle manual) ───────────
# Este alarm é colocado em ALARM manualmente durante manutenção
# para suprimir notificações do Composite Alarm
maintenance_alarm = cw.Alarm(
self, "MaintenanceWindowAlarm",
alarm_name="payment-maintenance-window",
alarm_description=(
"Set this alarm to ALARM manually during planned maintenance "
"to suppress composite alarm notifications."
),
metric=cw.Metric(
namespace="MyApp/Payments",
metric_name="MaintenanceWindowActive",
dimensions_map={"service": "payment-processor"},
statistic="Sum",
period=Duration.minutes(1),
),
threshold=0,
evaluation_periods=1,
comparison_operator=cw.ComparisonOperator.GREATER_THAN_THRESHOLD,
treat_missing_data=cw.TreatMissingData.NOT_BREACHING,
)
# ── Lambda de remediação ──────────────────────────────────────
remediation_fn = lambda_.Function(
self, "AlarmRemediationFn",
function_name="payment-alarm-remediation",
runtime=lambda_.Runtime.PYTHON_3_12,
handler="handler.lambda_handler",
code=lambda_.Code.from_asset("lambda/alarm_remediation"),
timeout=Duration.seconds(30),
)
# Permissão para o CloudWatch invocar a Lambda
remediation_fn.add_permission(
"CloudWatchInvoke",
principal=iam.ServicePrincipal("lambda.alarms.cloudwatch.amazonaws.com"),
source_arn=f"arn:aws:cloudwatch:{self.region}:{self.account}:alarm:payment-critical-composite",
)
# ── SNS Topic para notificações ───────────────────────────────
ops_topic = sns.Topic(
self, "OpsTopic",
topic_name="payment-ops-alerts",
)
ops_topic.add_subscription(
sns_subs.EmailSubscription("ops-team@company.com")
)
# ── Composite Alarm ───────────────────────────────────────────
composite_alarm = cw.CfnCompositeAlarm(
self, "PaymentCriticalComposite",
alarm_name="payment-critical-composite",
alarm_description=(
"Critical: payment errors AND latency anomaly detected simultaneously.\n"
"Suppressed during maintenance window.\n"
"**Runbook:** https://wiki.internal/runbooks/payment-critical"
),
alarm_rule=(
f'ALARM("{high_error_alarm.alarm_name}") '
f'AND ALARM("{high_latency_alarm.alarm_name}") '
f'AND NOT ALARM("{maintenance_alarm.alarm_name}")'
),
alarm_actions=[
ops_topic.topic_arn,
remediation_fn.function_arn,
],
ok_actions=[ops_topic.topic_arn],
# actions_suppressor: outro alarm que suprime ações (feature avançada)
# actions_suppressor="payment-maintenance-window",
)
Lambda handler — remediação automatizada
# lambda/alarm_remediation/handler.py
import json
import boto3
from typing import Any
ssm = boto3.client("ssm")
sns = boto3.client("sns")
def lambda_handler(event: dict, context: Any) -> None:
"""
Invocado diretamente pelo CloudWatch Alarm quando muda de estado.
O evento contém: AlarmName, NewStateValue, NewStateReason, StateChangeTime,
OldStateValue, Trigger (threshold/band info)
"""
print(json.dumps(event))
alarm_name = event.get("alarmData", {}).get("alarmName", event.get("AlarmName", "unknown"))
new_state = event.get("alarmData", {}).get("state", {}).get("value", event.get("NewStateValue", "unknown"))
reason = event.get("alarmData", {}).get("state", {}).get("reason", event.get("NewStateReason", ""))
change_time = event.get("alarmData", {}).get("state", {}).get("timestamp", event.get("StateChangeTime", ""))
if new_state != "ALARM":
# Ação de remediação só faz sentido ao entrar em ALARM
print(f"Alarm {alarm_name} changed to {new_state} — no action needed")
return
print(f"ALARM triggered: {alarm_name} at {change_time}")
print(f"Reason: {reason}")
# 1. Criar OpsItem no SSM OpsCenter para rastreamento
try:
ssm.create_ops_item(
Title=f"Payment Critical Alarm: {alarm_name}",
Description=(
f"CloudWatch Composite Alarm triggered at {change_time}.\n\n"
f"Reason: {reason}\n\n"
"Runbook: https://wiki.internal/runbooks/payment-critical"
),
Source="cloudwatch",
OperationalData={
"/aws/resources": {
"Value": json.dumps([{
"arn": f"arn:aws:cloudwatch::alarm:{alarm_name}"
}]),
"Type": "SearchableString",
}
},
Severity="2", # 1=Critical, 2=High, 3=Medium, 4=Low
Category="Availability",
Tags=[
{"Key": "Service", "Value": "payment-processor"},
{"Key": "AlarmName", "Value": alarm_name},
{"Key": "Environment", "Value": "production"},
],
)
print("SSM OpsItem created successfully")
except Exception as e:
print(f"Failed to create SSM OpsItem: {e}")
# 2. Enriquecimento adicional: ex. verificar se há deploy recente em andamento
# (chamada ao CodeDeploy, Deployment, etc. omitida por brevidade)
CLI — Criar e gerenciar alarms
# 1. Criar Composite Alarm via CLI
aws cloudwatch put-composite-alarm \
--alarm-name "payment-critical-composite" \
--alarm-description "Dispara quando erros E latência anômala ocorrem simultaneamente" \
--alarm-rule 'ALARM("payment-high-error-rate") AND ALARM("payment-high-latency-anomaly") AND NOT ALARM("payment-maintenance-window")' \
--alarm-actions \
"arn:aws:sns:us-east-1:123456789012:payment-ops-alerts" \
"arn:aws:lambda:us-east-1:123456789012:function:payment-alarm-remediation" \
--ok-actions "arn:aws:sns:us-east-1:123456789012:payment-ops-alerts"
# 2. Criar anomaly detector para latência
aws cloudwatch put-anomaly-detector \
--namespace "MyApp/Payments" \
--metric-name "ProcessingLatency" \
--stat "p95" \
--dimensions Name=service,Value=payment-processor Name=environment,Value=production
# 3. Criar alarm baseado no anomaly detector
aws cloudwatch put-metric-alarm \
--alarm-name "payment-high-latency-anomaly" \
--metrics '[
{
"Id": "m1",
"MetricStat": {
"Metric": {
"Namespace": "MyApp/Payments",
"MetricName": "ProcessingLatency",
"Dimensions": [
{"Name": "service", "Value": "payment-processor"},
{"Name": "environment", "Value": "production"}
]
},
"Stat": "p95",
"Period": 60
},
"ReturnData": true
},
{
"Id": "ad1",
"Expression": "ANOMALY_DETECTION_BAND(m1, 2)",
"Label": "ProcessingLatency (expected)",
"ReturnData": true
}
]' \
--comparison-operator GreaterThanUpperThreshold \
--threshold-metric-id ad1 \
--evaluation-periods 3 \
--datapoints-to-alarm 2 \
--treat-missing-data notBreaching
# 4. Simular manutenção: forçar alarm para ALARM state manualmente
# (coloca maintenance alarm em ALARM para suprimir composite)
aws cloudwatch set-alarm-state \
--alarm-name "payment-maintenance-window" \
--state-value ALARM \
--state-reason "Planned maintenance window 02:00-04:00 UTC"
# 5. Restaurar após manutenção
aws cloudwatch set-alarm-state \
--alarm-name "payment-maintenance-window" \
--state-value OK \
--state-reason "Maintenance window completed"
# 6. Listar estados de todos os alarms de pagamento
aws cloudwatch describe-alarms \
--alarm-name-prefix "payment-" \
--query 'MetricAlarms[*].{Name:AlarmName,State:StateValue,Reason:StateReason}'
aws cloudwatch describe-alarms \
--alarm-types CompositeAlarm \
--alarm-name-prefix "payment-" \
--query 'CompositeAlarms[*].{Name:AlarmName,State:StateValue,Rule:AlarmRule}'
# 7. Excluir período anômalo do modelo de anomaly detection
# (ex: excluir janela de incident de ontem do treinamento)
YESTERDAY_START=$(date -u -d 'yesterday 02:00' '+%Y-%m-%dT%H:%M:%S' 2>/dev/null || date -u -v-1d '+%Y-%m-%dT02:00:00')
YESTERDAY_END=$(date -u -d 'yesterday 06:00' '+%Y-%m-%dT%H:%M:%S' 2>/dev/null || date -u -v-1d '+%Y-%m-%dT06:00:00')
aws cloudwatch put-anomaly-detector \
--namespace "MyApp/Payments" \
--metric-name "ProcessingLatency" \
--stat "p95" \
--dimensions Name=service,Value=payment-processor Name=environment,Value=production \
--configuration "{
\"ExcludedTimeRanges\": [
{\"StartTime\": \"${YESTERDAY_START}\", \"EndTime\": \"${YESTERDAY_END}\"}
]
}"
Armadilhas comuns
1. Ciclos de dependência em Composite Alarms
[FATO] Dois Composite Alarms que referenciam um ao outro criam um ciclo que paralisa a avaliação de ambos. Não é possível deletar alarms em ciclo sem antes quebrar a dependência — defina AlarmRule = FALSE em um deles via set-alarm-state ou put-composite-alarm e então delete.
2. Anomaly Detection leva até 2 semanas para precisão máxima
[FATO] Nas primeiras horas após criação do detector, a banda é uma estimativa grosseira. Criar alarms baseados em anomaly detection imediatamente após o deploy pode gerar alarmes falsos frequentes. Aguarde pelo menos 3 dias para a banda estabilizar; 2 semanas para precisão ideal.
3. set-alarm-state é temporário — CloudWatch sobrescreve no próximo ciclo
[FATO] set-alarm-state força o estado do alarm mas esse estado é sobrescrito na próxima avaliação de métrica (no próximo período de evaluation). É útil para testes e para manutenções manuais temporárias, mas não persiste. Para supressão durante manutenção, use o padrão de Maintenance Window Alarm descrito acima.
4. Lambda action requer permissão explícita — console cuida, CDK não
[FATO] O console CloudWatch adiciona automaticamente a permissão lambda:InvokeFunction para o principal lambda.alarms.cloudwatch.amazonaws.com. Via CDK ou CLI, você precisa criar um lambda.Permission explicitamente com source_arn apontando para o ARN do alarm. Sem isso, o alarm cria a action mas a invocação falha silenciosamente (sem erro visível no alarm — o erro aparece apenas nos CloudWatch Logs da Lambda).
5. Actions Suppressor vs. NOT em AlarmRule
[CONSENSO] Há dois mecanismos para suprimir ações de Composite Alarms: (1) incluir NOT ALARM("maintenance-alarm") na AlarmRule — o alarm muda de estado mas não executa actions; (2) usar ActionsSuppressor no put-composite-alarm — o alarm muda de estado E suprime actions com um mecanismo de "wait" configurável. O segundo é mais robusto para janelas de manutenção longas pois permite configurar ActionsSuppressorWaitPeriod e ActionsSuppressorExtensionPeriod.
6. Custo de anomaly detection não é trivial em alta escala
[FATO] Cada detector custa $0.30/mês (além do custo da métrica). 100 métricas com anomaly detection = $30/mês apenas nos detectores. Para workloads com centenas de microserviços e múltiplas métricas por serviço, o custo escala rapidamente. Priorize anomaly detection para métricas de SLO críticas.
Exercício de reflexão
Você tem três microserviços — checkout, inventory, e notification — cada um com alarms individuais de HighErrorRate e HighLatency. Você quer criar uma arquitetura de observabilidade que:
-
Alerte de forma distinta quando apenas um serviço está degradado vs. quando múltiplos serviços estão degradados simultaneamente (o que indica um problema de infraestrutura compartilhada, não de serviço individual).
-
Modele a AlarmRule correta para um "CriticalSystemDegradation" Composite Alarm que dispara quando dois ou mais dos três serviços tiverem
HighErrorRateem ALARM simultaneamente. Escreva a expressão lógica — dica:A AND B OR A AND C OR B AND Cé equivalente a "2 ou mais de 3". -
O serviço
notificationtem tráfego muito baixo às 3h-6h UTC (menos de 10 requests/minuto). Durante esse período,HighErrorRatefrequentemente vai paraINSUFFICIENT_DATA. Como você configurariatreat_missing_datapara esse alarm, e que impacto isso teria no Composite Alarm? Há algum risco nessa escolha?
Recursos para aprofundar
- [FATO] Create a Composite Alarm: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Create_Composite_Alarm.html
- [FATO] Create an alarm based on anomaly detection: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Create_Anomaly_Detection_Alarm.html
- [FATO] Using CloudWatch Anomaly Detection: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Anomaly_Detection.html
- [FATO] Alarm evaluation and missing data: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/alarms-and-missing-data.html
- [FATO] PutCompositeAlarm API (AlarmRule syntax): https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutCompositeAlarm.html