为什么使用控制面板?
使用 CloudPeek 不一定需要控制面板:预设和 AI 小组件无需控制面板即可使用。当你想精确选择要监控的指标时,控制面板就很有价值:例如你自己的自定义指标、特定资源、指标数学、阈值或你挑选的警报。查找合适的命名空间和维度、编写指标数学和设置阈值,用键盘和大屏幕要容易得多,而 CloudWatch 已经提供了相应的工具。
这样,CloudWatch 控制面板就是你的监控清单:
- 每个小组件都可以固定。一个小组件可以包含一个或多个指标:一张折线图显示三个实例的 CPU,一张条形图显示你最大的五项费用,一个数字显示由两个指标计算得出的错误率。
- 每个控制面板都是一组相关的小组件。每个服务一个,支出一个,值班轮换一个。你可以从任意数量的控制面板和账户中固定小组件。
- 控制面板就是普通的 JSON,因此可以在 CloudFormation、Terraform、AWS CDK 或任何能写入字符串的工具中定义,并与它所监控的服务一起部署。
已经有控制面板?直接从中固定即可。也可以专门为手机创建一个小型控制面板,只放你想一眼看到的小组件。
在 AWS 控制台中设计
- 打开 CloudWatch 控制台,选择控制面板 › 创建控制面板,然后为其命名。
- 选择小部件类型:折线图、堆叠面积图、数字、仪表、条形图、饼图、表格、文本或警报状态。它们在 CloudPeek 中都能使用(请参阅小组件参考)。
- 在浏览选项卡上,选择一个命名空间,例如 ApplicationELB 或你自己的命名空间,然后勾选要放在此小部件上的指标。
- 在已绘制图表的指标选项卡上,设置每个指标的统计数据、周期和标签。选择添加数学来添加错误率等表达式,并取消勾选不想绘制的输入指标。
- 在选项选项卡上,为阈值添加水平注释,并设置 Y 轴的上下限。仪表需要同时设置最小值和最大值。
- 选择创建小部件,为它取一个简短的标题,然后保存控制面板。
在 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 中的样子如下:
{
"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 部署。要从你在控制台中设计的控制面板开始:
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:
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:
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 中通过编辑选择的标题、区域或时间范围都会保留,并应用于控制面板中的最新内容(请参阅编辑小组件)。
- 如果你删除控制面板或为其重命名,小组件会保留最后的数据,并显示控制面板已删除。
- 再次添加同一个小组件,会重新连接之前显示它的所有主屏幕小组件(请参阅再次添加同一个小组件)。