Painéis

Projetar painéis

Quando as predefinições e os widgets de IA não bastam, um painel do CloudWatch permite escolher suas métricas em uma tela grande, com o próprio seletor de métricas, a matemática e os limites do CloudWatch, e mantê-las no CloudFormation ou no Terraform.

Atualizado em 19 de outubro de 2026

Por que um painel?

Você não precisa de um painel para usar o CloudPeek: as predefinições e os widgets de IA funcionam sem um. Um painel vale a pena quando você quer escolher exatamente quais métricas acompanhar: suas próprias métricas personalizadas, recursos específicos, matemática de métricas, limites ou alarmes que você escolher. Encontrar o namespace e as dimensões certos, escrever matemática de métricas e definir limites é muito mais fácil com um teclado e uma tela grande, e o CloudWatch já tem a ferramenta para isso.

Assim, um painel do CloudWatch é simplesmente a sua lista do que acompanhar:

  • Cada widget é algo que você pode fixar. Um widget agrupa uma ou mais métricas: a CPU de três instâncias em um gráfico de linhas, seus cinco maiores custos em um gráfico de barras, uma taxa de erros calculada a partir de duas métricas em um número.
  • Cada painel é um conjunto de widgets que andam juntos. Um por serviço, um para gastos, um para a escala de plantão. Você pode fixar widgets de quantos painéis e contas quiser.
  • Um painel é JSON puro, então pode ser definido no CloudFormation, no Terraform, no AWS CDK ou em qualquer outra coisa que consiga escrever uma string, e implantado com os serviços que monitora.

Já tem painéis? Fixe widgets direto deles. Ou crie um pequeno só para o celular, apenas com os widgets que você quer ver de relance.

Projetar no console da AWS

  1. Abra o console do CloudWatch, escolha Painéis › Criar painel e dê um nome a ele.
  2. Escolha um tipo de widget: Linha, Área empilhada, Número, Medidor, Barra, Pizza, Tabela, Texto ou Status do alarme. Todos funcionam no CloudPeek (consulte a referência de widgets).
  3. Na aba Procurar, escolha um namespace, como ApplicationELB ou um dos seus, e marque as métricas que você quer neste widget.
  4. Na aba Métricas em gráfico, defina a estatística, o período e o rótulo de cada métrica. Escolha Adicionar matemática para uma expressão como uma taxa de erros e desmarque as entradas que você não quer desenhar.
  5. Na aba Opções, adicione anotações horizontais para os limites e defina o mínimo e o máximo do eixo Y. Um medidor precisa dos dois.
  6. Escolha Criar widget, dê a ele um título curto e salve o painel com Salvar.

Abra o painel no CloudPeek e cada widget aparece como vai ficar na sua Tela de Início. Fixe os que quiser ou adicione-os com Criar Widget › De um Painel (consulte Criar um widget).

Facilite a leitura no celular

Um widget na Tela de Início tem poucos centímetros de largura. Alguns hábitos facilitam muito a leitura:

  • Uma pergunta por widget. “A API está saudável?” fica mais legível como um número de taxa de erros e um medidor de latência do que como um gráfico com oito linhas.
  • Poucas séries por gráfico. Nos widgets médios e grandes, a legenda lista até quatro séries e depois “Mais N”. Um widget pequeno não tem legenda.
  • Títulos curtos. No iPhone e no iPad, o widget em linha da Tela Bloqueada mostra cerca de 18 caracteres do título, e o circular, cerca de 8.
  • Escolha a visualização certa para uma olhada rápida. Um número com "sparkline": true mostra o valor mais recente e sua tendência; um medidor o mostra dentro de um intervalo que você define; um gráfico de barras classifica itens. Veja como cada tipo fica.
  • Defina o intervalo que importa. O start do próprio widget substitui o do painel e, sem nenhum dos dois, o CloudPeek mostra as últimas 3 horas. Todo widget informa a janela de tempo que abrange.
  • Rótulos em vez de IDs. Dê às métricas um label, para que a legenda diga “Checkout API” em vez de “app/checkout-api/50dc6c495c0c9188”. Um rótulo dinâmico como ${PROP('Dim.ServiceName')} dá a cada série o nome do valor de uma dimensão.

Exemplo: um painel de saúde da API

Três widgets para um Application Load Balancer: a taxa de erros como número, a latência p99 como medidor e as solicitações comparadas aos erros em um gráfico de linhas. No CloudPeek, eles ficam assim:

A taxa de erros é calculada a partir de duas métricas ocultas; a linha de 5xx tem sua própria escala à direita.
api-health.jsonBaixar
{
  "start": "-PT3H",
  "widgets": [
    {
      "type": "metric",
      "x": 0,
      "y": 0,
      "width": 6,
      "height": 6,
      "properties": {
        "title": "5xx error rate",
        "view": "singleValue",
        "region": "us-east-1",
        "period": 300,
        "sparkline": true,
        "metrics": [
          [ { "expression": "100 * FILL(m2, 0) / m1", "label": "Errors (%)", "id": "e1" } ],
          [ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "stat": "Sum", "id": "m1", "visible": false } ],
          [ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "stat": "Sum", "id": "m2", "visible": false } ]
        ]
      }
    },
    {
      "type": "metric",
      "x": 6,
      "y": 0,
      "width": 6,
      "height": 6,
      "properties": {
        "title": "Latency p99",
        "view": "gauge",
        "region": "us-east-1",
        "stat": "p99",
        "period": 300,
        "yAxis": { "left": { "min": 0, "max": 2 } },
        "metrics": [
          [ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "label": "p99 (s)" } ]
        ]
      }
    },
    {
      "type": "metric",
      "x": 12,
      "y": 0,
      "width": 12,
      "height": 6,
      "properties": {
        "title": "Requests and errors",
        "view": "timeSeries",
        "region": "us-east-1",
        "stat": "Sum",
        "period": 300,
        "metrics": [
          [ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "app/checkout-api/50dc6c495c0c9188", { "label": "Requests" } ],
          [ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "label": "5xx", "yAxis": "right", "color": "#d62728" } ]
        ]
      }
    }
  ]
}
  • Taxa de erros: a expressão 100 * FILL(m2, 0) / m1 divide as respostas 5xx pelas solicitações. FILL conta um período sem erros como zero em vez de deixar uma lacuna. As duas entradas têm "visible": false, então só a taxa é mostrada.
  • Latência: um medidor usa o min e o max do eixo Y como intervalo (de 0 a 2 segundos aqui). Sem eles, o CloudPeek considera de 0 a 100.
  • Solicitações e erros: "yAxis": "right" dá à contagem de 5xx sua própria escala, para que um punhado de erros não fique achatado diante de milhares de solicitações. "." repete o valor da mesma posição na linha acima.
  • Substitua app/checkout-api/50dc6c495c0c9188 pelo nome do seu balanceador de carga, que está no ARN dele depois de loadbalancer/, ou deixe o CloudFormation ou o Terraform preenchê-lo, como mostrado abaixo.

Gerenciar como código

Projete um painel no console até ele ficar do jeito certo e depois copie o JSON dele em Ações › Visualizar/editar origem para o seu código de infraestrutura. A partir daí, ele é revisado, versionado e implantado junto com os serviços que monitora, e fica igual em todas as contas e regiões onde você o implanta.

Você não precisa colocar os painéis em código. Um painel que você edita no console também é lido pelo CloudPeek na próxima atualização.

Se um painel for gerenciado pelo CloudFormation ou pelo Terraform, trate o console como um rascunho: as alterações que você salva nele são substituídas na próxima implantação. Teste uma ideia no console e depois copie a origem de volta para o seu código (Ações › Visualizar/editar origem).

Mantenha o JSON no controle de versão e implante-o com put-dashboard. Para começar com um painel que você projetou no console:

Shell
aws cloudwatch get-dashboard \
  --dashboard-name Checkout-API \
  --query DashboardBody --output text > api-health.json

aws cloudwatch put-dashboard \
  --dashboard-name Checkout-API \
  --dashboard-body file://api-health.json

put-dashboard substitui o painel inteiro, então o arquivo é sempre a versão completa e definitiva.

Um AWS::CloudWatch::Dashboard recebe o JSON como string. Envolva-o em !Sub e você pode preencher valores da mesma pilha, como a dimensão do balanceador de carga, em vez de colar IDs:

CloudFormation
  CheckoutApiDashboard:
    Type: AWS::CloudWatch::Dashboard
    Properties:
      DashboardName: Checkout-API
      DashboardBody: !Sub
        - |
          {
            "start": "-PT3H",
            "widgets": [
              {
                "type": "metric", "x": 0, "y": 0, "width": 6, "height": 6,
                "properties": {
                  "title": "5xx error rate",
                  "view": "singleValue",
                  "region": "${AWS::Region}",
                  "period": 300,
                  "sparkline": true,
                  "metrics": [
                    [ { "expression": "100 * FILL(m2, 0) / m1", "label": "Errors (%)", "id": "e1" } ],
                    [ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "${Alb}", { "stat": "Sum", "id": "m1", "visible": false } ],
                    [ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "stat": "Sum", "id": "m2", "visible": false } ]
                  ]
                }
              },
              {
                "type": "metric", "x": 6, "y": 0, "width": 6, "height": 6,
                "properties": {
                  "title": "Latency p99",
                  "view": "gauge",
                  "region": "${AWS::Region}",
                  "stat": "p99",
                  "period": 300,
                  "yAxis": { "left": { "min": 0, "max": 2 } },
                  "metrics": [
                    [ "AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", "${Alb}", { "label": "p99 (s)" } ]
                  ]
                }
              },
              {
                "type": "metric", "x": 12, "y": 0, "width": 12, "height": 6,
                "properties": {
                  "title": "Requests and errors",
                  "view": "timeSeries",
                  "region": "${AWS::Region}",
                  "stat": "Sum",
                  "period": 300,
                  "metrics": [
                    [ "AWS/ApplicationELB", "RequestCount", "LoadBalancer", "${Alb}", { "label": "Requests" } ],
                    [ ".", "HTTPCode_Target_5XX_Count", ".", ".", { "label": "5xx", "yAxis": "right", "color": "#d62728" } ]
                  ]
                }
              }
            ]
          }
        - Alb: !GetAtt LoadBalancer.LoadBalancerFullName
  • LoadBalancer é o AWS::ElasticLoadBalancingV2::LoadBalancer do mesmo modelo; o LoadBalancerFullName dele é exatamente o valor que a dimensão LoadBalancer do CloudWatch espera.
  • Dentro de !Sub, o CloudFormation lê cada ${…} como uma variável dele. Escreva um rótulo dinâmico do CloudWatch como ${LAST} na forma ${!LAST}.
  • Os painéis são globais, mas cada widget indica sua região. ${AWS::Region} usa a região da pilha.

Um aws_cloudwatch_dashboard recebe o JSON como string. Escreva-o em HCL e envolva-o em jsonencode, e você pode usar referências, variáveis e expressões for em vez de colar IDs:

Terraform
resource "aws_lb" "checkout" {
  name    = "checkout-api"
  subnets = ["subnet-11111111", "subnet-22222222"]
}

locals {
  alb    = aws_lb.checkout.arn_suffix # the LoadBalancer dimension: app/checkout-api/…
  region = "us-east-1"                # where the load balancer is
}

resource "aws_cloudwatch_dashboard" "checkout_api" {
  dashboard_name = "Checkout-API"
  dashboard_body = jsonencode({
    start = "-PT3H"
    widgets = [
      {
        type = "metric", x = 0, y = 0, width = 6, height = 6
        properties = {
          title     = "5xx error rate"
          view      = "singleValue"
          region    = local.region
          period    = 300
          sparkline = true
          metrics = [
            [{ expression = "100 * FILL(m2, 0) / m1", label = "Errors (%)", id = "e1" }],
            ["AWS/ApplicationELB", "RequestCount", "LoadBalancer", local.alb, { stat = "Sum", id = "m1", visible = false }],
            [".", "HTTPCode_Target_5XX_Count", ".", ".", { stat = "Sum", id = "m2", visible = false }],
          ]
        }
      },
      {
        type = "metric", x = 6, y = 0, width = 6, height = 6
        properties = {
          title  = "Latency p99"
          view   = "gauge"
          region = local.region
          stat   = "p99"
          period = 300
          yAxis  = { left = { min = 0, max = 2 } }
          metrics = [
            ["AWS/ApplicationELB", "TargetResponseTime", "LoadBalancer", local.alb, { label = "p99 (s)" }],
          ]
        }
      },
      {
        type = "metric", x = 12, y = 0, width = 12, height = 6
        properties = {
          title  = "Requests and errors"
          view   = "timeSeries"
          region = local.region
          stat   = "Sum"
          period = 300
          metrics = [
            ["AWS/ApplicationELB", "RequestCount", "LoadBalancer", local.alb, { label = "Requests" }],
            [".", "HTTPCode_Target_5XX_Count", ".", ".", { label = "5xx", yAxis = "right", color = "#d62728" }],
          ]
        }
      },
    ]
  })
}
  • O arn_suffix de um aws_lb é exatamente o valor que a dimensão LoadBalancer do CloudWatch espera.
  • O Terraform lê ${…} em uma string como interpolação. Escreva um rótulo dinâmico do CloudWatch como ${LAST} na forma $${LAST}.
  • Prefere manter o JSON em um arquivo? dashboard_body = file("api-health.json") também funciona, ou templatefile() para preencher valores.
  • Para colocar sob o Terraform um painel que você criou no console, adicione um bloco import com o nome dele como id ou execute terraform import aws_cloudwatch_dashboard.checkout_api Checkout-API.

O AWS CDK, o Pulumi e outras ferramentas funcionam da mesma forma: qualquer coisa que consiga definir o corpo de um painel pode definir o que o CloudPeek mostra.

Como as alterações chegam ao seu celular

  • Sempre que um widget fixado é atualizado a partir da AWS, o CloudPeek lê o painel de novo, então uma alteração que você salva no console ou implanta a partir do código aparece na próxima atualização. Para vê-la na hora, toque no botão de atualizar do widget.
  • Os widgets no CloudPeek acompanham o widget de painel de origem quando você o move, redimensiona, muda o título dele ou altera as métricas. Se o CloudPeek não conseguir identificar qual widget era, ele continua mostrando a última versão que encontrou.
  • Um título ou uma região que você deu ao widget na prévia de Criar Widget, e um título, uma região ou um intervalo de tempo que você escolheu com Editar no CloudPeek, são mantidos e aplicados sobre o que o painel tiver (consulte Editar um widget).
  • Se você excluir ou renomear o painel, o widget mantém os últimos dados e mostra Painel excluído.
  • Adicionar o mesmo widget de novo reconecta os widgets da Tela de Início que o mostravam (consulte Adicionar o mesmo widget de novo).