4. CloudWatch Logs深度使用
CloudWatch Logs 是 AWS 可观测性体系里最贴近“原始事实”的一层。指标告诉你“系统变慢了”,追踪告诉你“慢在哪个调用”,而日志往往回答“为什么慢、当时发生了什么”。要真正用好它,不能只停留在控制台点开日志看几行,而需要理解它的四层结构:日志组(Log Group)是逻辑容器,日志流(Log Stream)是同一来源下的连续事件序列,指标过滤器(Metric Filter)把日志文本转成可告警的数值指标,订阅过滤器(Subscription Filter)把日志实时投递到下游做处理或归档。再往上,Logs Insights 提供了一套查询语言,让我们在大量日志里做聚合、关联和模式识别。
日志组与日志流:先想清楚“谁写、写多久、怎么找”
日志组通常按应用或组件划分,例如 /aws/lambda/order-service、/aws/ecs/checkout-api、/app/payment/gateway。命名建议体现“环境 + 服务 + 组件”,因为日志组是权限、保留期和加密策略的最小管理单元。日志流则是同一日志组内按来源切分的序列,常见来源包括 Lambda 执行环境实例、ECS 任务 ID、EC2 实例 ID 或容器名。一个容易踩的坑是:日志流不会自动清理,如果日志组保留期设为“永不过期”,而日志流数量又随实例频繁重建而增长,控制台会变得难以浏览。因此保留期应显式设置,例如生产环境 30 天、审计类 365 天、调试类 7 天。
写入日志有两种典型方式:一是通过 SDK 的 PutLogEvents 直接写入指定日志流;二是由 CloudWatch Agent、Lambda 或 ECS 的 awslogs 驱动自动写入。无论哪种方式,都建议在日志中保留结构化字段,例如 JSON 格式的 requestId、userId、latencyMs、statusCode,因为后续的指标过滤器和 Logs Insights 查询都依赖这些字段做精确匹配。
指标过滤器:把日志里的“异常信号”变成可告警的指标
指标过滤器解决的是“日志很多但没人看”的问题。它的核心是:在日志组上定义过滤模式,匹配到的事件会生成一个自定义指标数据点。过滤模式可以是简单字符串、带通配符的模式,也可以是 JSON 属性匹配。例如,我们想统计订单服务中 HTTP 500 的数量,可以定义如下过滤模式:
{ $.statusCode = 500 }
如果日志是纯文本,则可以用空格分隔的模式,例如 ERROR Exception 表示同一事件中同时出现 ERROR 和 Exception。指标过滤器支持设置指标命名空间、指标名、维度以及默认值。默认值很关键:当某段时间没有匹配事件时,CloudWatch 会按默认值上报,通常设为 0,这样告警不会因为“没有数据”而误判。一个实用的告警配置是:对 500 错误数指标设置 5 分钟周期、统计方式为 Sum、阈值大于 5 持续 2 个周期触发。这样既能捕捉突发错误,又不会被单次抖动打扰。
订阅过滤器:让日志实时流向该去的地方
订阅过滤器用于把日志组中的日志实时推送到下游,常见目标包括 Lambda、Kinesis Data Streams、Kinesis Data Firehose 和 OpenSearch Service。它的价值在于:CloudWatch Logs 本身适合查询和短期保留,但不适合做复杂流处理、跨账号集中归档或长期低成本存储。通过订阅过滤器,可以把日志送到 S3 做长期归档,或送到 OpenSearch 做全文检索和仪表盘。
订阅过滤器同样使用过滤模式,但要注意每个日志组默认最多只能有两个订阅过滤器。如果同时需要“全量归档”和“错误告警”两条链路,通常的做法是:一条订阅过滤器匹配全部日志送往 Firehose 归档,另一条匹配错误模式送往 Lambda 做实时告警。订阅过滤器依赖目标资源的权限,配置时需要确保 CloudWatch Logs 服务有权调用目标,例如 Lambda 的资源策略或 Kinesis 的 IAM 角色。若投递失败,日志组上会出现 SubscriptionFilterDeliveryFailure 相关指标,应纳入监控。
Logs Insights 查询语法:从“翻日志”到“问日志”
Logs Insights 的查询语言由一组命令组成,按顺序执行,常见命令包括 fields、filter、stats、sort、limit、parse、display。一个典型的查询是:先筛选时间范围,再过滤错误,然后按接口聚合平均延迟。例如:
fields @timestamp, requestId, path, latencyMs, statusCode
| filter statusCode >= 500
| stats avg(latencyMs) as avgLatency, count(*) as errCount by path
| sort errCount desc
| limit 20
这段查询的含义是:取出时间戳、请求 ID、路径、延迟和状态码;只保留 5xx;按路径统计平均延迟和错误数;按错误数降序排列,取前 20 条。结果可以直接在控制台查看,也可以导出为 CSV。对于非 JSON 日志,可以用 parse 命令提取字段,例如 parse @message "user=* method=* path=* status=*" as user, method, path, status。需要注意的是,parse 的通配符匹配是贪婪的,字段顺序和分隔符必须与日志格式严格一致,否则会解析出空值。
Logs Insights 还支持 bin() 做时间分桶,例如 stats count(*) by bin(5m) 可以画出 5 分钟粒度的错误趋势。结合 filter @message like /timeout/ 可以快速定位超时类问题。查询性能与日志量、时间范围、过滤条件都相关,建议先用较窄的时间范围和较强的过滤条件缩小数据集,再逐步放宽。
常见日志分析任务与判断依据
实际排障中,几类任务出现频率最高。第一类是“错误突增定位”:用 stats count(*) by bin(1m), statusCode 观察错误随时间的变化,若某个状态码在某一分钟突然抬升,再结合 requestId 去追踪具体调用链。第二类是“慢请求分析”:用 stats avg(latencyMs), pct(latencyMs, 95), max(latencyMs) by path 找出长尾接口,p95 比平均值更能反映用户体验。第三类是“异常模式识别”:用 filter @message like /Exception|ERROR|Timeout/ 统计不同异常类型的出现次数,判断是偶发还是系统性问题。第四类是“日志断流排查”:如果某个日志组长时间没有新事件,先检查日志流是否还在写入、订阅过滤器是否投递失败、以及采集端是否因权限或网络问题停止上报。
把这几层串起来看,CloudWatch Logs 的使用路径就清晰了:日志来源写入日志组和日志流,指标过滤器负责把关键信号转成可告警指标,订阅过滤器负责把日志实时送到下游做归档或检索,Logs Insights 负责在需要时做交互式分析。实际工作中,建议先为每个服务定义好日志组命名和保留期,再针对核心错误和延迟字段配置指标过滤器与告警,最后按合规和检索需求配置订阅过滤器。这样既能控制成本,又能在故障发生时快速从“指标异常”下钻到“日志证据”。