Vector 编码选项重构实战:encoding.only_fields、encoding.except_fields与timestamp_format完全指南
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
本篇技术指南围绕 Vector 在 0.9.0 版本中对 sink 编码配置的重构展开:废弃根级encoding字符串选项,改为结构化的encoding.*子选项,从而支持字段白名单、字段黑名单与时间戳序列化格式的自定义。文章以 官方变更通告 为骨架,结合仓库内 Transformer 实现、编码配置解析 与测试用例,帮助你掌握新配置的完整参数语义、升级路径以及字段裁剪在源码层面的工作原理,读完即可在真实 pipeline 中配置字段级编码控制。
背景:为什么要把扁平encoding拆成encoding.*
在 Vector 0.9.0 之前,sink 的encoding是一个扁平的字符串配置,例如encoding: "json",只能指定编解码器,无法控制"哪些字段参与编码"。为此 Vector 在 PR #1915 中引入了encoding.*子选项体系,该 PR 同时新增了encoding.only_fields与encoding.except_fields两个选项(见 0.9.0 版本发布记录)。
重构之后,编码配置从"单一 codec 字符串"演变为"codec + 字段裁剪 + 时间戳格式"的完整配置块,官方通告将其总结为四个核心子选项:
| 子选项 | 作用 |
|---|---|
encoding.only_fields | 只编码列出的字段(白名单) |
encoding.except_fields | 编码除列出的字段以外的所有字段(黑名单) |
encoding.codec | 使用的编解码器(如json) |
encoding.timestamp_format | 自定义时间戳字段的序列化格式 |
升级指南:从旧配置迁移到新配置
升级过程非常简单,核心变化是把encoding: "json"改写为嵌套的encoding:映射。下面是官方通告中的完整升级示例(字段裁剪与时间戳格式均为可选):
sinks: my-sink: type: "..." - encoding: "json" + encoding: + codec: "json" + except_fields: ["_meta"] # optional + timestamp_format: "rfc3339" # optional将示例落地为一个真实可运行的 sink 配置(以 Elasticsearch sink 为例),效果如下:
sinks: my_es_sink: type: elasticsearch inputs: ["my_source"] endpoints: ["http://localhost:9200"] encoding: codec: "json" except_fields: ["idx", "timestamp"] # 移除仅用于路由的字段 timestamp_format: "unix_ms"深入理解四个子选项的语义
encoding.codec
指定事件被序列化成的编解码器。它是SerializerConfig的核心,决定了编码后字节流的形态(JSON、Avro、原生格式等)。从 EncodingConfig 定义 可以看到,整个编码配置由SerializerConfig(通过 serde flatten 展开)与Transformer两部分组成:codec 负责"怎么序列化",而 Transformer 负责"序列化前对事件做什么加工"。
encoding.only_fields:白名单字段裁剪
只保留列出的字段,其余字段在编码前全部被移除。典型的应用场景是数据最小化:上游事件携带了大量内部字段,但下游只关心timestamp、message、host、user_id等少数几个字段时,可以用白名单大幅压缩传输体积。
encoding.except_fields:黑名单字段裁剪
编码除列出的字段以外的所有字段。典型场景是敏感信息剥离:例如路由元数据、内部调试字段(如官方示例中的_meta)不需要发送到下游,用黑名单精确剔除即可,无需枚举其余全部字段。
encoding.timestamp_format:时间戳序列化格式
控制事件中所有Timestamp类型字段在编码时的呈现形式。根据 Transformer 的 TimestampFormat 枚举 与 CUE schema 定义,支持以下取值:
| 取值 | 含义 |
|---|---|
rfc3339 | RFC 3339 格式(如2020-12-01T01:02:03Z),也是时间戳的默认序列化方式 |
unix | Unix 秒级时间戳 |
unix_ms | Unix 毫秒级时间戳 |
unix_us | Unix 微秒级时间戳 |
unix_ns | Unix 纳秒级时间戳 |
unix_float | 浮点数 Unix 时间戳(微秒除以1e6得到,见 transformer.rs) |
不同下游对时间戳格式的偏好差异很大(如 InfluxDB 偏爱纳秒整数、日志系统偏爱 RFC 3339 字符串),该选项让同一个事件可以按目标系统的要求做序列化适配。
源码级原理:Transformer 如何完成字段裁剪
字段白名单、黑名单与时间戳格式的落地实现全部集中在 lib/codecs/src/encoding/transformer.rs 的Transformer类型中。它由三个可选字段组成(struct 定义):
only_fields: Option<Vec<ConfigValuePath>>except_fields: Option<Vec<ConfigValuePath>>timestamp_format: Option<TimestampFormat>
事件在序列化之前会调用Transformer::transform,处理顺序如下(transform 方法):
apply_except_fields:先删除黑名单字段;apply_only_fields:再按白名单重建事件;apply_timestamp_format:最后统一改写时间戳格式。
需要注意:这些规则目前只作用于日志事件——transform通过event.maybe_as_log_mut()判断,指标与 trace 事件不受影响(注释说明)。
白名单的内部实现:重建事件对象
apply_only_fields的实现方式是"先整体取出旧值、再按白名单字段放回":将事件值替换为空对象后,遍历only_fields中的路径,从旧值中取出对应字段重新插入。测试deserialize_and_transform_only验证了嵌套路径(a.b.c)、数组索引(c[0].y)、带引号的含点键名("g.z")等场景的裁剪行为(见 transformer.rs 测试)。
黑名单的内部实现:逐字段删除
apply_except_fields遍历黑名单路径并逐一log.remove。测试deserialize_and_transform_except确认了删除语义:删除a.b.c不影响同父级下的a.b.d,删除b会连带移除b[1].x这样的子路径,而c[0].y被删后c[0].x仍然保留(见 transformer.rs 测试)。
互斥校验与配置合法性
only_fields与except_fields不能同时列出同一个字段。Transformer::new会调用validate_fields做互斥校验,一旦发现重叠立即返回错误:except_fields and only_fields should be mutually exclusive(见 validate_fields)。测试exclusivity_violation与deny_unknown_fields分别验证了互斥规则与未知字段拒绝行为(transformer.rs 测试),前者在 TOML 配置only_fields = ["Doop"]与except_fields = ["Doop"]同时出现时反序列化直接失败。
与 service 语义的联动:裁剪不丢元数据
一个值得注意的细节是:当裁剪删除的字段恰好是带service语义(semantic meaning)的字段时,Transformer 不会简单地丢弃其值,而是把它移入事件元数据的dropped_fields(apply_only_fields、apply_except_fields)。这样后续需要通过 service 字段给指标打标签的场景仍能通过get_by_meaning("service")取到该值。测试only_fields_with_service与except_fields_with_service完整验证了这一行为(transformer.rs 测试)。
字段路径语法:支持嵌套与数组索引
only_fields与except_fields中填写的是 Vector 的 lookup 路径语法,而非简单的顶层键名。从 config.rs 的反序列化测试 可以看到,配置既可以是 TOML 也可以是 JSON,路径支持:
- 嵌套字段:
a.b.c、thing.service - 数组索引:
a.b[0]、c[0].y - 含点键名转义:
"g.z"(用引号包裹含点的字面键)
对应 JSON 形态的完整配置示例:
{ "codec": "json", "only_fields": ["a.b[0]"], "except_fields": ["ignore_me"], "timestamp_format": "unix" }该 JSON 在 EncodingConfig 测试 中被完整反序列化,可验证only_fields、except_fields与timestamp_format三者的正确解析。需要注意的是,同一配置块内only_fields与except_fields涉及的路径不可重叠。
实测验证:Elasticsearch sink 中的黑名单应用
仓库在 src/sinks/elasticsearch/tests.rs 中提供了allows_using_except_fields集成测试,展示了黑名单在真实 sink 中的用法:构建一个idx、timestamp字段被列入except_fields的编码 Transformer,然后将带foo、idx等字段的日志事件送入编码器,最终输出的 JSON 只包含保留字段,路由用的idx与时间戳字段被剔除。这印证了except_fields在"字段仅用于内部路由、不必外发"场景下的标准实践。
完整实战示例与注意事项
综合以上内容,一个同时使用白名单与时间戳格式的完整配置如下:
sinks: my_http_sink: type: http inputs: ["processed_logs"] uri: "http://example.com/ingest" encoding: codec: "json" only_fields: ["@timestamp", "message", "host", "user_id"] timestamp_format: "unix_ms"使用要点小结:
codec是必填项,其余三个子选项均可选;only_fields与except_fields不可同时引用同一字段,否则配置校验失败;- 字段裁剪与时间戳改写发生在序列化之前,由
Transformer统一完成,属于纯内存加工,不影响原始事件在 pipeline 中的后续流转; - 规则目前仅作用于日志事件,配置指标或 trace 场景时需注意;
rfc3339是时间戳的默认格式,未配置timestamp_format时保持原样;- 若需同时配置 framing(帧分隔方式),可使用 EncodingConfigWithFraming 支持的
framing子块,其反序列化行为同样有测试覆盖(见 config.rs 测试)。
进一步探索
- 官方通告原文:website/content/en/highlights/2020-03-04-encoding-only-fields-except-fields.md
- Transformer 核心实现与全部测试:lib/codecs/src/encoding/transformer.rs
- 编码配置结构(含 framing):lib/codecs/src/encoding/config.rs
- 配置项的 CUE schema(字段类型与枚举定义):website/cue/reference/components/generated/schema_definitions/codecs_encoding_transformer_transformer.cue
- 0.9.0 版本发布记录(PR #1915):website/cue/reference/releases/0.9.0.cue
- 字段裁剪在 schema 管理中的延伸用法(
only_fields函数):website/content/en/guides/level-up/managing-schemas.md
【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考