Vector aws_cloudwatch_logs Sink 完全指南:将日志流稳定写入 AWS CloudWatch Logs
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
AWS CloudWatch Logs 是 AWS 生态中最常用的日志汇聚目标之一。本指南围绕 Vector 官方aws_cloudwatch_logssink 组件展开,讲解它的核心配置参数、模板化分区机制、底层发送状态机、批处理与分块策略、AWS 认证与最小 IAM 权限要求,并结合仓库源码与集成测试给出可复现的实战配置。读完本文,你将能够基于当前仓库版本独立完成「日志源 → Vector → CloudWatch Logs」的管道搭建,并理解为什么该 sink 需要按(group, stream)分区串行发送、事件时间戳需要满足什么窗口约束,以及如何在出现限流时正确调优。
组件总览:稳定的批量日志出口
sink类型的aws_cloudwatch_logs组件把日志事件发布到 AWS CloudWatch Logs(对应文档元数据位于 website/cue/reference/components/sinks/aws_cloudwatch_logs.cue)。其组件画像如下:
| 维度 | 值 | 说明 |
|---|---|---|
| 开发状态 | stable | 生产可用的稳定组件 |
| 投递保证 | at_least_once | 至少一次投递,配合端到端确认机制使用 |
| 出站方式 | batch | 以批量请求方式发送 |
| 服务商 | AWS | 面向 AWS CloudWatch Logs API |
| 输入类型 | 仅logs | metrics与traces均不支持 |
| 有状态 | 否 | stateful: false |
| 健康检查 | 开启 | 基于DescribeLogGroups |
| 确认机制 | 支持 | acknowledgements可配置 |
在 Rust 侧,该组件由src/sinks/aws_cloudwatch_logs/目录下的 8 个文件实现(mod.rs、config.rs、sink.rs、request.rs、request_builder.rs、service.rs、healthcheck.rs、retry.rs),底层基于aws-sdk-cloudwatchlogs官方 SDK。
快速上手:最小配置与完整示例
仓库内置了两份可直接参考的示例配置(生成于 website/generated/example-configs/sinks/aws_cloudwatch_logs/)。
最小配置(minimal.yaml):
sinks: my_sink_id: type: aws_cloudwatch_logs inputs: - my-source-or-transform-id encoding: codec: json group_name: group-name stream_name: stream-{{ host }}完整配置(advanced.yaml):
sinks: my_sink_id: type: aws_cloudwatch_logs inputs: - my-source-or-transform-id compression: none create_missing_group: true create_missing_stream: true dangerously_allow_unconfined_template_resolution: false encoding: codec: json endpoint: http://127.0.0.0:5000/path/to/service group_name: group-name region: us-east-1 stream_name: stream-{{ host }}其中group_name与stream_name是仅有的两个必填参数(在 generated/aws_cloudwatch_logs.cue 中均标记为required: true)。encoding也是必填项。其余参数均可省略并使用默认值。
核心配置参数详解
以下参数定义来自 website/cue/reference/components/sinks/generated/aws_cloudwatch_logs.cue,并与 config.rs 中的CloudwatchLogsSinkConfig结构体一一对应。
必填参数
group_name(string,模板语法):目标日志组名称,例如group-name或group-{{ file }}。在配置校验阶段会被编译为受限模板(ConfinedTemplate)。stream_name(string,模板语法):目标日志流名称。官方文档与 config.rs 的注释都强调:一个日志流同一时刻只允许一个写入者,若多个 Vector 实例写入同一日志组,stream_name必须包含保证每个实例唯一的标识(官方示例stream-{{ host }}就是基于主机名区分)。encoding:编码配置,codec支持json与text(见 aws_cloudwatch_logs.cue 中encoding.codec.enum)。该配置同时决定了 sink 接受的输入类型。
可选参数
| 参数 | 默认值 | 说明 |
|---|---|---|
region | 无(继承 AWS 默认区域解析链) | 目标服务所在区域,如us-east-1;也可通过AWS_DEFAULT_REGION环境变量提供 |
endpoint | null | 自定义端点,用于 AWS 兼容服务(如 LocalStack),示例http://127.0.0.0:5000/path/to/service |
create_missing_group | true | 目标日志组不存在时动态创建;注意:创建组后会忽略create_missing_stream直接创建第一条日志流(因为新建的组必然没有流) |
create_missing_stream | true | 目标日志流不存在时动态创建 |
retention.enabled | false | 创建新日志组时是否设置保留策略 |
retention.days | 0 | 保留天数,仅当enabled为true时生效,且必须是 AWS 允许的固定取值(见下文) |
compression | none | 压缩算法。生成的 schema 枚举包含gzip、none、snappy、zlib、zstd(generated/aws_cloudwatch_logs.cue) |
kms_key | null | 加密日志数据的 KMS 密钥 ARN,创建日志组时传入 |
tags | null | 键值对形式,创建时应用到日志组与日志流 |
auth | 默认凭据链 | AWS 认证配置,详见「认证与权限」一节 |
request.* | 全局默认 | 出站 HTTP 请求设置(超时、限流、重试等) |
tls.* | 自动启用 | TLS 配置,enabled_default: true |
acknowledgements | 默认 | 端到端确认开关 |
dangerously_allow_unconfined_template_resolution | false | 危险开关:关闭该 sink 全部模板限制校验(详见下文模板节) |
保留策略的合法取值
retention.days并非任意整数。在 config.rs 的retention_days反序列化函数中,枚举了 AWS 允许的全部取值:1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653(单位:天)。传入其他值会直接导致配置校验失败并报错one of allowed values: [...]。
模板、分区与流命名:多实例写入的正确姿势
group_name与stream_name都支持 Vector 模板语法(在事件字段上插值,如{{ file }}、{{ host }})。两者的差异在于模板限制强度:
group_name使用受限模板(ConfinedTemplate):默认必须在配置校验期(startup validation)被证明是「可受控」的。若模板没有任何静态前缀(如纯{{ group }}),会被拒绝;而events-{{ env }}这种带静态前缀的模板可以通过。对应实现与测试见 config.rs(confinement_rejects_unconfined_group_name、confinement_allows_prefixed_group_name)。stream_name使用不受限模板(UnconfinedTemplate),但默认仍受运行时限制(runtime confinement)约束;只有显式开启dangerously_allow_unconfined_template_resolution: true才会同时关闭启动期与运行期校验。该开关被标记为DANGEROUS — disables a security control,开启后任何能控制模板字段的日志生产者都可能把事件写入任意 key/路径,生产环境应尽量避免。
在 sink.rs 中,CloudwatchPartitioner以渲染后的(group, stream)二元组(即CloudwatchKey)作为分区键进行batched_partitioned聚合。每个分区拥有独立的发送服务链(service stack),且并发度强制为 1(见 service.rs 注释「Concurrency limit is 1 because we need token from previous request」)。这是因为 CloudWatch Logs 的PutLogEvents要求携带上一个请求返回的sequenceToken,同一日志流内的写入必须严格串行。这一机制也正是「一个流同时只有一个写入者」约束的根源——这也是官方建议多实例场景下stream_name必须带实例唯一标识(如{{ host }})的原因。
批处理、分块与大小限制
批处理默认值
默认批处理配置定义在 config.rs 的CloudwatchLogsDefaultBatchSettings,与 CUE 元数据一致:
max_events:10_000(条)max_bytes:1_048_576(字节,即 1 MiB,基于未压缩/未序列化前的事件大小估算)timeout_secs:1.0(秒,批的最长滞留时间)
对应 YAML:
batch: max_events: 10000 max_bytes: 1048576 timeout_secs: 1.024 小时分块
AWS 要求一次PutLogEvents请求内的日志时间戳跨度不能超过 24 小时。因此 service.rs 的process_events会先把事件按时间戳升序排序,再二分切分为若干「24 小时窗口」的子批次,逐批发送并串联 sequence token。大部分场景下事件天然在 24h 内,走的是快速路径(直接整体发送)。
单条消息与批量大小上限
request_builder.rs 定义了与 AWS 限额严格对齐的尺寸常量:
const EVENT_SIZE_OVERHEAD: usize = 50; // 空消息时 InputLogEvent 的估算开销 const BATCH_SIZE_OVERHEAD: usize = 26; // 每个日志事件额外 26 字节 const MAX_EVENT_SIZE: usize = 1024 * 1024; // 单条事件 1 MiB const MAX_MESSAGE_SIZE: usize = MAX_EVENT_SIZE - EVENT_SIZE_OVERHEAD - BATCH_SIZE_OVERHEAD;- 单条消息编码后超过
MAX_MESSAGE_SIZE(约 1 MiB − 76 字节)会被丢弃并发出AwsCloudwatchLogsMessageSizeError内部事件(对应测试test_rejects_oversized_log_event验证了这一点); - 批量总大小的计算口径为「所有消息 UTF-8 长度之和 + 每条 26 字节」,与 AWS PutLogEvents API 文档 的限额计算方式一致(
ByteSizeOf实现见 request_builder.rs)。
底层发送状态机:一次请求的完整旅程
request.rs 用枚举状态机串起了一次 CloudWatch 写入的完整流程:
DescribeStream ──(ResourceNotFound 且 create_missing_group)──▶ CreateGroup │ │ ▼ ▼ 找到流 ◀──(无流 且 create_missing_stream)── CreateStream ◀──(保留策略开启时插入)── PutRetentionPolicy │ ▼ PutLogEvents(携带 uploadSequenceToken)──▶ 若有 24h 分块则继续 Put ──▶ 回传 nextSequenceToken各状态的行为:
- DescribeStream:以
stream_name为前缀调用DescribeLogStreams查找目标流。若日志组不存在且create_missing_group=true,转入CreateGroup;若流不存在且create_missing_stream=true,转入CreateStream;否则报NoStreamsFound。 - CreateGroup:调用
CreateLogGroup(带kms_key与tags)。ResourceAlreadyExistsException被宽容处理。若retention.enabled为真,先执行PutRetentionPolicy再创建流;无论create_missing_stream取值如何,创建组后都会强制创建第一条流(新组必然没有流)。 - CreateStream:调用
CreateLogStream,同样宽容处理ResourceAlreadyExistsException。 - Put:调用
PutLogEvents,使用上一次响应的nextSequenceToken作为本次的sequenceToken;若存在 24h 分块则循环发送,最后通过 oneshot 通道把 token 回传给服务层,供下一个请求复用(request.rs)。
事件在进入状态机前,还会经过 request_builder.rs 的构建:渲染 group/stream 模板 → 提取事件时间戳(无时间戳则用当前时间)→ 应用 transformer → 编码 → 尺寸校验。
事件时间戳窗口:14 天回看 + 2 小时前瞻
CloudWatch Logs 对事件时间戳有硬性约束(最老 14 天,最新未来 2 小时)。sink.rs 在进入批处理器之前对每个请求做了一次时间过滤:
let start = (now - Duration::days(14) + Duration::minutes(5)).timestamp_millis(); let end = (now + Duration::hours(2)).timestamp_millis();即时间戳落在[now − 14天 + 5分钟, now + 2小时]区间之外的事件会被静默过滤(不发送)。集成测试 integration_tests.rs(cloudwatch_insert_out_of_range_timestamp)专门构造了 15 天前、125 分钟前等越界时间戳,验证只有窗口内的事件被写入。若你的上游数据存在较大时钟偏差,需要提前在 transform 阶段修正时间戳,否则会被 sink 直接丢弃。
AWS 认证与最小 IAM 权限
凭据解析顺序
auth与各 AWS 组件共用一套认证体系(定义在 website/cue/reference/components/aws.cue 的how_it_works.aws_authentication)。Vector 按以下顺序解析凭据:
auth.access_key_id与auth.secret_access_key配置项;AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY环境变量;- Web Identity Token 凭据(含 EKS,到期自动刷新);
- ECS 任务 IAM 角色凭据(到期自动刷新);
- 主目录
~/.aws/credentials凭据文件; AWS_PROFILE指定的命名 profile;- IAM 实例角色(仅 EC2,需启用 IMDSv2)。
auth子参数还包括assume_role(跨账号角色扮演)、region(STS 请求区域)、load_timeout_secs(默认 5 秒)、profile(默认default)以及imds相关超时与重试设置。若最终未找到任何凭据,健康检查会失败并记录错误日志。
IAM 权限清单
aws_cloudwatch_logs.cue 明确列出了该 sink 需要的最小 IAM 权限:
| 动作 | 何时必需 |
|---|---|
CreateLogGroup | create_missing_group为true时 |
CreateLogStream | create_missing_stream为true时 |
DescribeLogGroups | 健康检查 |
DescribeLogStreams | 始终需要(定位目标流) |
PutLogEvents | 始终需要(写入日志) |
如果关闭了自动创建并静态指定了已存在的组/流,则只需DescribeLogStreams、PutLogEvents(外加健康检查所需的DescribeLogGroups)。
重试策略与健康检查
重试逻辑
retry.rs 的CloudwatchRetryLogic对以下错误判定为可重试:
PutLogEvents/DescribeLogStreams/CreateLogStream返回的ServiceUnavailableException(服务不可用);- 底层
is_retriable_error判定为可重试的 AWS 错误(如ThrottlingException限流)。
单元测试 retry.rs(test_throttle_retry)用一条 400 状态的ThrottlingException响应验证了限流场景的重试判定。重试退避遵循 Fibonacci 序列(见 util/service.rs 中TowerRequestConfig的注释),可通过request.retry_attempts、request.retry_initial_backoff_secs、request.retry_max_duration_secs等参数调整。
健康检查
healthcheck.rs 的实现:调用DescribeLogGroups(limit=1, prefix=group_name)并校验返回的组名与配置完全一致。特殊分支:
group_name为动态模板时跳过检查(提示日志);create_missing_group=true时跳过检查(组会被自动创建);- 否则找不到组即报
NoLogGroup错误。
提示:限流/超时类问题可参考 util/retries.rs 中关于
request.timeout_secs与batch.max_bytes、compression关系的调优建议;在带宽受限或事件较大的场景,开启compression: gzip通常能显著降低请求体大小。
数据面链路验证:集成测试怎么说
仓库在 integration_tests.rs 中通过CLOUDWATCH_ADDRESS(默认http://localhost:4566,即 LocalStack)对该 sink 做了端到端验证,覆盖的关键行为包括:
cloudwatch_insert_log_event:随机 100 字节 × 11 行日志写入后可完整回读,内容一致;cloudwatch_insert_log_events_sorted:模拟乱序时间戳,验证发送前的排序逻辑;cloudwatch_insert_out_of_range_timestamp:验证时间窗口过滤;cloudwatch_dynamic_group_and_stream_creation:验证create_missing_group/create_missing_stream动态创建能力。
这些测试同时通过run_and_assert_sink_compliance校验了组件在 sink 合规性(AWS_SINK_TAGS)方面的表现。如果你需要本地复现,可先启动 LocalStack 的 CloudWatch 服务,再设置CLOUDWATCH_ADDRESS指向其地址,通过endpoint参数接入(参考 config.rs 的create_client对RegionOrEndpoint的处理)。
一个可直接上手的综合配置
结合以上要点,下面是一份面向生产的多实例部署配置(包含注释):
sinks: cloudwatch_logs: type: aws_cloudwatch_logs inputs: - my_app_logs encoding: codec: json # 按应用划分日志组;日志组模板默认需要静态前缀(受限模板) group_name: /vector/app-{{ file }} # 多实例必须保证流名实例级唯一,避免并发写同一流 stream_name: stream-{{ host }} region: us-east-1 compression: gzip # 减小请求体积 create_missing_group: true create_missing_stream: true retention: enabled: true days: 30 # 必须是 AWS 允许的枚举值 batch: max_events: 10000 max_bytes: 1048576 timeout_secs: 1.0 request: timeout_secs: 60 retry_attempts: 5 auth: assume_role: arn:aws:iam::123456789098:role/vector-log-shipper acknowledgements: enabled: true使用前可用vector validate校验配置,用vector generate aws_cloudwatch_logs生成可编辑的骨架配置(generate_config实现见 config.rs)。
总结
aws_cloudwatch_logssink 是一个成熟(stable)、面向日志、批量出站的 AWS 组件。用好它的关键在于理解三条底层约束:同一日志流串行写入(sequence token 机制,驱动stream_name唯一性设计)、24 小时批内时间跨度(自动分块)与14 天/2 小时时间戳窗口(超窗事件被丢弃)、以及与 AWS 限额严格对齐的消息/批量大小。在此基础上,合理组合模板分区、compression、retention、auth.assume_role与request重试参数,即可构建稳定可靠的 CloudWatch Logs 日志管道。相关实现细节均可直接回到 src/sinks/aws_cloudwatch_logs/ 与 website/cue/reference/components/sinks/ 中继续深挖。
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考