控制面板

设计控制面板

当预设和 AI 小组件无法满足需求时,你可以借助 CloudWatch 控制面板,在大屏幕上使用 CloudWatch 自带的指标选择器、数学表达式和阈值来选择指标,并将其保存在 CloudFormation 或 Terraform 中。

更新于 2026年10月19日

为什么使用控制面板?

使用 CloudPeek 不一定需要控制面板:预设和 AI 小组件无需控制面板即可使用。当你想精确选择要监控的指标时,控制面板就很有价值:例如你自己的自定义指标、特定资源、指标数学、阈值或你挑选的警报。查找合适的命名空间和维度、编写指标数学和设置阈值,用键盘和大屏幕要容易得多,而 CloudWatch 已经提供了相应的工具。

这样,CloudWatch 控制面板就是你的监控清单:

  • 每个小组件都可以固定。一个小组件可以包含一个或多个指标:一张折线图显示三个实例的 CPU,一张条形图显示你最大的五项费用,一个数字显示由两个指标计算得出的错误率。
  • 每个控制面板都是一组相关的小组件。每个服务一个,支出一个,值班轮换一个。你可以从任意数量的控制面板和账户中固定小组件。
  • 控制面板就是普通的 JSON,因此可以在 CloudFormation、Terraform、AWS CDK 或任何能写入字符串的工具中定义,并与它所监控的服务一起部署。

已经有控制面板?直接从中固定即可。也可以专门为手机创建一个小型控制面板,只放你想一眼看到的小组件。

在 AWS 控制台中设计

  1. 打开 CloudWatch 控制台,选择控制面板 › 创建控制面板,然后为其命名。
  2. 选择小部件类型:折线图、堆叠面积图、数字、仪表、条形图、饼图、表格、文本或警报状态。它们在 CloudPeek 中都能使用(请参阅小组件参考)。
  3. 在浏览选项卡上,选择一个命名空间,例如 ApplicationELB 或你自己的命名空间,然后勾选要放在此小部件上的指标。
  4. 在已绘制图表的指标选项卡上,设置每个指标的统计数据、周期和标签。选择添加数学来添加错误率等表达式,并取消勾选不想绘制的输入指标。
  5. 在选项选项卡上,为阈值添加水平注释,并设置 Y 轴的上下限。仪表需要同时设置最小值和最大值。
  6. 选择创建小部件,为它取一个简短的标题,然后保存控制面板。

在 CloudPeek 中打开该控制面板,每个小组件都会按它在主屏幕上的样子绘制出来。固定你想要的小组件,或者通过创建小组件 › 来自控制面板添加它们(请参阅创建小组件)。

让它在手机上易于阅读

主屏幕上的小组件只有几厘米宽。养成以下几个习惯,能让它容易阅读得多:

  • 每个小组件只回答一个问题。“API 是否正常?”用一个错误率数字加一个延迟仪表来呈现,比用一张有八条线的图表更易读。
  • 每张图表少放几个数据系列。在中号和大号小组件上,图例最多列出四个系列,其余显示为“还有 N 项”。小号小组件完全没有图例。
  • 标题要短。在 iPhone 和 iPad 上,锁定屏幕的内联小组件大约保留标题的 18 个字符,圆形小组件大约保留 8 个。
  • 为一瞥选择合适的视图。带有 "sparkline": true 的数字显示最新值及其趋势;仪表显示该值在你设定的范围中所处的位置;条形图则对各项进行排名。请参阅每种类型的外观。
  • 设置你关心的时间范围。小组件自身的 start 会覆盖控制面板的设置;两者都没有时,CloudPeek 显示过去 3 小时。每个小组件都会注明它涵盖的时间段。
  • 用标签代替 ID。为指标设置 label,这样图例会显示“Checkout API”,而不是“app/checkout-api/50dc6c495c0c9188”。像 ${PROP('Dim.ServiceName')} 这样的动态标签会用某个维度的值为每个系列命名。

示例:API 健康状况控制面板

为一个 Application Load Balancer 设计的三个小组件:以数字显示的错误率、以仪表显示的 p99 延迟,以及在折线图上对比的请求数与错误数。它们在 CloudPeek 中的样子如下:

错误率由两个隐藏的指标计算得出;5xx 折线在右侧有自己的刻度。
api-health.json下载
{
  "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" } ]
        ]
      }
    }
  ]
}
  • 错误率:表达式 100 * FILL(m2, 0) / m1 用 5xx 响应数除以请求数。FILL 将没有错误的周期计为零,而不是留下空缺。两个输入都设置了 "visible": false,因此只显示错误率。
  • 延迟:仪表使用 Y 轴的 min 和 max 作为其范围(此处为 0 到 2 秒)。如果没有设置这两个值,CloudPeek 会假定范围为 0 到 100。
  • 请求数和错误:"yAxis": "right" 让 5xx 计数使用单独的刻度,这样少量错误就不会在数千个请求面前被压成一条平线。"." 表示沿用上一行同一位置的值。
  • 将 app/checkout-api/50dc6c495c0c9188 替换为负载均衡器 ARN 中 loadbalancer/ 之后的名称,或者如下文所示,让 CloudFormation 或 Terraform 来填入。

以代码方式管理

在控制台中设计控制面板,直到满意为止,然后从操作 › 查看/编辑源复制它的 JSON 到你的基础设施代码中。从此,它会与它所监控的服务一起审查、进行版本控制和部署,并且在你部署到的每个账户和区域中都完全相同。

你不一定要把控制面板写成代码。在控制台中编辑的控制面板,同样会在下次刷新时被 CloudPeek 读取。

如果控制面板确实由 CloudFormation 或 Terraform 管理,就把控制台当作草稿本:你在那里保存的更改会在下次部署时被覆盖。先在控制台中尝试想法,再把源复制回代码中(操作 › 查看/编辑源)。

将 JSON 保存在版本控制中,并使用 put-dashboard 部署。要从你在控制台中设计的控制面板开始:

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 会替换整个控制面板,因此该文件始终是完整的唯一事实来源。

AWS::CloudWatch::Dashboard 以字符串形式接收 JSON。用 !Sub 包裹它,就可以填入同一堆栈中的值(例如负载均衡器的维度),而无需粘贴 ID:

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 是同一模板中的 AWS::ElasticLoadBalancingV2::LoadBalancer;它的 LoadBalancerFullName 正是 CloudWatch 的 LoadBalancer 维度所需的值。
  • 在 !Sub 中,CloudFormation 会把每个 ${…} 都当作它自己的变量。请将 ${LAST} 之类的 CloudWatch 动态标签写成 ${!LAST}。
  • 控制面板是全局的,但每个小组件都会指定自己的区域。${AWS::Region} 使用堆栈所在的区域。

aws_cloudwatch_dashboard 以字符串形式接收 JSON。用 HCL 编写并用 jsonencode 包裹,就可以使用引用、变量和 for 表达式,而无需粘贴 ID:

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" }],
          ]
        }
      },
    ]
  })
}
  • aws_lb 的 arn_suffix 正是 CloudWatch 的 LoadBalancer 维度所需的值。
  • Terraform 会把字符串中的 ${…} 当作插值。请将 ${LAST} 之类的 CloudWatch 动态标签写成 $${LAST}。
  • 想把 JSON 保留为单独的文件?也可以使用 dashboard_body = file("api-health.json"),或者用 templatefile() 来填入值。
  • 要让 Terraform 接管你在控制台中创建的控制面板,请添加一个以其名称作为 id 的 import 块,或运行 terraform import aws_cloudwatch_dashboard.checkout_api Checkout-API。

AWS CDK、Pulumi 等其他工具的用法相同:任何能设置控制面板正文的工具,都能定义 CloudPeek 显示的内容。

更改如何同步到你的手机

  • 每次已固定的小组件从 AWS 刷新时,CloudPeek 都会重新读取控制面板,因此你在控制台中保存或通过代码部署的更改会在下次刷新时显示。要立即看到更改,请轻点小组件的刷新按钮。
  • 当你移动控制面板小组件、调整其大小、更改其标题或指标时,CloudPeek 中的小组件都会随之更新。如果 CloudPeek 无法分辨原来是哪个小组件,它会继续显示找到的最后一个版本。
  • 你在创建小组件的预览中为它设置的标题或区域,以及你在 CloudPeek 中通过编辑选择的标题、区域或时间范围都会保留,并应用于控制面板中的最新内容(请参阅编辑小组件)。
  • 如果你删除控制面板或为其重命名,小组件会保留最后的数据,并显示控制面板已删除。
  • 再次添加同一个小组件,会重新连接之前显示它的所有主屏幕小组件(请参阅再次添加同一个小组件)。