Vector 0.22 升级指南:破坏性变更、VRL 模板字符串与 17 个废弃 Transform 的迁移实践

发布时间:2026/9/14 17:28:55
Vector 0.22 升级指南:破坏性变更、VRL 模板字符串与 17 个废弃 Transform 的迁移实践 Vector 0.22 升级指南破坏性变更、VRL 模板字符串与 17 个废弃 Transform 的迁移实践【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vectorVector 0.22.0 是一次包含多项破坏性变更breaking changes的重要版本。本文基于仓库中的官方升级指南2022-05-03-0-22-0-upgrade-guide.md系统梳理三类破坏性变更——gcp_stackdriver_metrics配置结构调整、VRL 模板字符串支持、encode_key_value/encode_logfmt引号包裹行为变化——以及 0.23.0 即将移除的 17 个废弃 transform 的完整迁移方案并结合当前仓库源码给出每项变更的实现级印证帮助你在升级时快速定位并改写配置。0.22.0 版本变更总览0.22.0 的变更清单分为两大块破坏性变更3 项gcp_stackdriver_metricssink 配置结构调整VRL 语言新增模板字符串template strings支持encode_key_value与encode_logfmt编码器的引号包裹行为变化弃用声明1 项已被remap以及reduce替代的多个 transform 将在 0.23.0 中被最终移除以下逐一展开。破坏性变更一gcp_stackdriver_metrics配置结构调整变更内容gcp_stackdriver_metricssink 的配置现在与gcp_stackdriver_logs保持一致resource字段下不再需要额外的labels子节来承载资源标签标签直接平铺在resource内部。旧配置与新版配置对照旧配置0.22 之前sinks: my_sink_id: type: gcp_stackdriver_metrics inputs: [my-source-or-transform-id] credentials_path: /path/to/credentials.json project_id: vector-123456 resource: type: global labels: projectId: vector-123456 instanceId: Twilight zone: us-central1-a新配置0.22 起sinks: my_sink_id: type: gcp_stackdriver_metrics inputs: [my-source-or-transform-id] credentials_path: /path/to/credentials.json project_id: vector-123456 resource: type: global projectId: vector-123456 instanceId: Twilight zone: us-central1-a核心差异只有一个resource.labels这一层被去掉projectId、instanceId、zone等标签键值直接作为resource的平铺字段。源码印证新配置结构是如何定义的从当前仓库源码看该 sink 的配置定义在 src/sinks/gcp/stackdriver/metrics/config.rs。其中与resource相关的字段声明为/// The monitored resource to associate the metrics with. pub(super) resource: gcp::GcpTypedResource,即resource直接采用gcp::GcpTypedResource类型而非“嵌套 labels 的包装结构”这正是配置中平铺写法在代码侧的对应物。同一文件还定义了其他关键配置项可作为升级后完整配置的参照project_id: String— 指标发布的目标 GCP 项目 IDresource: gcp::GcpTypedResource— 与指标关联的被监控资源default_namespace: String— 无命名空间的指标使用的默认命名空间默认值为namespace由default_metric_namespace_value()提供auth— 通过#[serde(flatten)]平铺展开的GcpAuthConfig即credentials_path、api_key等认证字段直接写在 sink 顶层而不是嵌套在auth子节里endpoint— 默认端点为https://monitoring.googleapis.com请求 URI 在validate()中被拼接为/v3/projects/{project_id}/timeSeries。认证配置GcpAuthConfig定义在 src/gcp.rs支持credentials_path服务账号密钥文件与 API key 两种方式并处理了 GCE 元数据服务的隐式令牌metadata server token刷新逻辑。迁移要点如果你的配置里仍有resource.labels一层删除该层、将标签上移一层即可其余字段credentials_path、project_id、default_namespace等保持不变。破坏性变更二VRL 支持模板字符串语法说明VRLVector Remap Language的字符串现在支持模板插值在字符串中使用{{ 变量名 }}占位符即可嵌入变量的值。beverage coffee preference I love to drink {{ beverage }}! assert!(preference I love to drink coffee!)三条重要限制占位符必须是一个简单变量名且该变量必须能解析为字符串string。不能直接写路径或表达式# 不合法42 是整数不是字符串 stars 42 sky There are {{ stars }} in the sky.需要先显式转换为字符串stars to_string(42) sky There are {{ stars }} in the sky.不支持路径path占位符。以下写法不合法message The message is {{ .message }}.正确做法是先把字段值赋给变量message .message message The message is {{ message }}.转义与原始字符串如果确实需要在字符串中写入字面量{{/}}可以用\{{和\}}转义也可以使用原始字符串s...assert!(\{{ right here \}} s{{ right here }})为什么这是破坏性变更对升级者而言风险点在于0.22 之前不含{{语义的 VRL 字符串如果字符串内容里恰好出现了{{ 标识 }}形态例如处理模板文本、正则样例、日志样本数据升级后其含义会从字面量变为插值。升级后建议用vector validate校验配置中的 VRL 脚本对包含{{字面量内容的字符串改用s...原始字符串或\{{转义写法检查依赖字符串拼接逻辑的断言/过滤条件确认插值结果符合预期。破坏性变更三encode_key_value与encode_logfmt的引号包裹行为变化行为对比此前只有包含空白字符的键或值才会被双引号包裹从 0.22 起包含空白字符和/或双引号的键与值都会被双引号包裹且值中原有的双引号会被转义。这一变更使encode_logfmt与其他生态库对齐到 logfmt 的[定义规范]kr/logfmt规范。encode_logfmt的输出示例变化# 0.22 之前 lvlinfo msg{some:val} # 0.22 及之后 lvlinfo msg{\some\:\val\}源码印证编码实现的位置从当前仓库源码结构看logfmt 编码的核心函数位于 lib/vector-common/shared/src/lib.rsencode_logfmt模块。日志编码器的封装实现为 lib/codecs/src/encoding/format/logfmt.rs其中LogfmtSerializer实现EncoderEventtrait内部直接调用上述共享实现impl EncoderEvent for LogfmtSerializer { type Error vector_common::Error; fn encode(mut self, event: Event, buffer: mut BytesMut) - Result(), Self::Error { let log event.as_log(); let string encode_logfmt::encode_value(log.value())?; buffer.extend_from_slice(string.as_bytes()); Ok(()) } }这说明所有走logfmt/key_value编码器的 sinkfile sink 的encoding.logfmt、各 HTTP sink 的编码器等共享同一份转义逻辑行为变更是全局一致的。迁移要点若下游解析器依赖值中裸双引号不转义的旧格式例如msg{some:val}直接按 JSON 解析升级到 0.22 后需同步调整解析逻辑以处理{\some\:\val\}形态若下游是标准 logfmt 解析器如 Go 的kr/logfmt、多数 Java/Python 实现新行为反而修正了原来含引号但不含空格的值不加引号导致的解析歧义属于兼容性收益。弃用声明17 个废弃 transform 将在 0.23.0 移除背景remaptransform 引入时一批旧 transform 被标记为废弃并从文档中移除但实现仍保留在 Vector 中。0.22 的升级指南明确宣布这些 transform 将在 0.23.0 中最终移除同时merge由reduce替代。将移除的 transform 完整清单Transform替代方案add_fieldsremapadd_tagsremapansi_stripperremapstrip_ansi_escape_codesaws_cloudwatch_logs_subscription_parserremapparse_aws_cloudwatch_log_subscription_messagecoercerremapto_bool!/to_int!等concatremapjoin!grok_parserremapparse_grok!json_parserremapparse_jsonkey_value_parserremapparse_key_value!logfmt_parserremapparse_logfmt!mergereduceregex_parserremapparse_regex!remove_fieldsremapdelremove_tagsremapdelrename_fieldsremapdel 赋值splitremapsplittokenizerremapparse_tokens!从当前仓库的源码结构看src/transforms/目录下已不存在coercer.rs、tokenizer.rs、add_fields.rs等对应文件印证了这批 transform 已在新版本中彻底移除——当前仓库即处于移除之后的状态因此下面的迁移对照表既是升级指南也是这批 transform 历史行为的完整档案。逐项迁移对照add_fields# Before transforms: add_fields: type: add_fields inputs: [some_input] fields: parent: child2: value2 # After transforms: add_fields: type: remap inputs: [some_input] source: | .parent.child2 value2add_tags# Before transforms: add_tags: type: add_tags inputs: [some_input] tags: some_tag: some_value # After transforms: add_tags: type: remap inputs: [some_input] source: | .tags.some_tag some_valueansi_stripper# Before transforms: ansi_stripper: type: ansi_stripper inputs: [some_input] # After transforms: ansi_stripper: type: remap inputs: [some_input] drop_on_error: false source: | .message strip_ansi_escape_codes(string!(.message))aws_cloudwatch_logs_subscription_parser# Before transforms: aws_cloudwatch_logs_subscription_parser: type: aws_cloudwatch_logs_subscription_parser inputs: [some_input] # After transforms: aws_cloudwatch_logs_subscription_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | parse_aws_cloudwatch_log_subscription_message!(.message)coercercoercer支持对多个字段指定目标类型bool/float/int/string/timestamp迁移时用 VRL 的对应强制转换函数逐字段表达!后缀表示出错时丢弃事件与旧 transform 的严格模式语义对应# Before transforms: coercer: type: coercer inputs: [some_input] types: some_bool: bool some_float: float some_int: int some_string: string some_timestamp: timestamp # After transforms: coercer: type: remap inputs: [some_input] source: | .some_bool to_bool!(.some_bool) .some_float to_float!(.some_float) .some_int to_int!(.some_int) .some_string to_string!(.some_string) .some_timestamp to_timestamp!(.some_timestamp)concat# Before transforms: concat: type: concat inputs: [some_input] items: [month, day, year] target: date joiner: / # After transforms: concat: type: remap inputs: [some_input] drop_on_error: false source: | .date join!([.month, .day, .year], /)grok_parser迁移时注意旧的types中timestamp带时间格式%表示时间戳解析remap 版本用parse_timestamp!显式表达# Before transforms: grok_parser: type: grok_parser inputs: [some_input] pattern: %{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message} types: timestamp: timestamp|% level: string message: string # After transforms: grok_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | parse_grok!(.message, %{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}) .timestamp parse_timestamp!(.timestamp, format: %)json_parser# Before transforms: json_parser: type: json_parser inputs: [some_input] # After transforms: json_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | object!(parse_json(.message))key_value_parser# Before transforms: key_value_parser: type: key_value_parser inputs: [some_input] # After transforms: key_value_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | parse_key_value!(.message)logfmt_parser# Before transforms: logfmt_parser: type: logfmt_parser inputs: [some_input] # After transforms: logfmt_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | parse_logfmt!(.message)merge→reducemerge由reduce替代需要通过starts_when与merge_strategies表达原来的按._partial分组拼接message逻辑# Before transforms: merge: type: merge inputs: [some_input] # After transforms: merge: type: reduce inputs: [some_input] starts_when: ._partial true merge_strategies: message: concatregex_parser旧的types中timestamp|%d/%m/%Y:%H:%M:%S %z这类类型|格式复合声明迁移后拆分为parse_regex! 逐字段类型转换两步# Before transforms: regex_parser: type: regex_parser inputs: [some_input] patterns: - ^(?Phost[\w\.]) - (?Puser[\w]) (?Pbytes_in[\d]) \[(?Ptimestamp.*)\] (?Pmethod[\w]) (?Ppath.*) (?Pstatus[\d]) (?Pbytes_out[\d])$ types: bytes_in: int timestamp: timestamp|%d/%m/%Y:%H:%M:%S %z status: int bytes_out: int # After transforms: regex_parser: type: remap inputs: [some_input] drop_on_error: false source: | . | parse_regex!(.message, [#^(?Phost[\w\.]) - (?Puser[\w]) (?Pbytes_in[\d]) \[(?Ptimestamp.*)\] (?Pmethod[\w]) (?Ppath.*) (?Pstatus[\d]) (?Pbytes_out[\d])$#]) .bytes_in to_int!(.bytes_in) .some_timestamp parse_timestamp!(.some_timestamp, %d/%m/%Y:%H:%M:%S %z) .status to_int!(.status) .bytes_out to_int!(.bytes_out)原文档示例中.some_timestamp的字段名为示意写法实际迁移时请以你自己 pattern 中命名捕获组的真实字段名为准。remove_fields# Before transforms: remove_fields: type: remove_fields inputs: [some_input] fields: [parent.child] # After transforms: remove_fields: type: remap inputs: [some_input] source: | del(.parent.child)remove_tags# Before transforms: remove_tags: type: remove_tags inputs: [some_input] tags: [some_tag] # After transforms: remove_tags: type: remap inputs: [some_input] source: | del(.tags.some_tag)rename_fieldsdel的返回值是删除前的值这一特性正好用来完成取值 删除两步合一的重命名# Before transforms: rename_fields: type: rename_fields inputs: [some_input] fields: new_name: [old_name] # After transforms: rename_fields: type: remap inputs: [some_input] source: | .new_name del(.old_name)split# Before transforms: split: type: split inputs: [some_input] field_names: [remote_addr, user_id, timestamp, message, status, bytes] types: status: int bytes: int # After transforms: split: type: remap inputs: [some_input] drop_on_error: false source: | values split(.message) .remote_addr values[0] .user_id values[1] .timestamp values[2] .message values[3] .status to_int!(values[4]) .bytes to_int!(values[5])tokenizertokenizer按空白分词不区分引号内的空格remap 版本使用parse_tokens!# Before transforms: tokenizer: type: tokenizer inputs: [some_input] field_names: [remote_addr, ident, user_id, timestamp, message, status, bytes] types: status: int bytes: int # After transforms: tokenizer: type: remap inputs: [some_input] drop_on_error: false source: | values parse_tokens!(.message) .remote_addr values[0] .user_id values[1] .timestamp values[2] .message values[3] .status to_int!(values[4]) .bytes to_int!(values[5])注意原文档示例中tokenizer的field_names有 7 项但示例源码只映射了 6 项迁移时请根据实际字段个数调整索引。升级操作清单结合以上全部变更推荐的升级步骤全文检索配置中的废弃 transform 类型名add_fields、coercer、grok_parser、json_parser等 17 个按上表逐一改写为remap/reduce检查gcp_stackdriver_metricssink若resource下存在labels层去掉该层并将标签平铺审查 VRL 脚本确认没有字符串意外引入{{ var }}插值语义需要字面量{{/}}的地方改用\{{/\}}转义或s...原始字符串评估 logfmt/key_value 编码的下游影响确认消费端能处理含引号的值带转义引号的新输出格式运行vector validate校验改写后的配置确认所有 VRL 脚本编译通过、组件类型有效。参考文件升级指南原文website/content/en/highlights/2022-05-03-0-22-0-upgrade-guide.mdgcp_stackdriver_metricssink 配置实现src/sinks/gcp/stackdriver/metrics/config.rsGCP 认证配置GcpAuthConfigsrc/gcp.rslogfmt 编码器封装lib/codecs/src/encoding/format/logfmt.rslogfmt/key_value 核心编码实现lib/vector-common/shared/src/lib.rs需要说明的是0.22 升级指南是 2022 年 5 月针对当时版本发布的本文引用的源码路径与实现细节如GcpTypedResource平铺结构、src/transforms/中旧 transform 已不存在等均以当前仓库的实际状态为准两者在时间上存在代差若你在较新版本上排查同类问题建议以当前仓库源码为最终依据。【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考