数据截至 (上游 commit 384d66161cb1)
从 YAML 到产物 — Weaver 编译、Rego 策略、schema 迁移
本章讲机器:同一份 YAML 怎么变成人读文档、各语言代码,以及构建期有哪些闸门保证「改约定不闯祸」。三件事:① Weaver 生成,② Rego 策略,③ schema 版本迁移。
3.1 Weaver:唯一的编译器
YAML 本身不会自己变成文档。干这活的是 Weaver——一个外部工具,以固定版本的 Docker 容器引入(otel/weaver:v0.25.1,dependencies.Dockerfile:6)。本仓只调用它,不含它的源码。
Weaver 在本仓有两个主要用法(都在 Makefile):
| make 目标 | Weaver 子命令 | 产出 |
|---|---|---|
table-generation | registry update-markdown | 把字段表回填进 docs/**/*.md 里的标记区块(Makefile:164-178) |
registry-generation | registry generate markdown | 生成 docs/registry/ 下的属性注册表文档(Makefile:185-197) |
两者都把 model/(源)、templates/(模板)、docs/(目标)挂进容器。心智模型:
model/**/*.yaml ─┐
templates/** ├─▶ [ weaver 容器 ] ─▶ docs/**/*.md (表格被替换/生成)
│ ─▶ (下游仓:各语言常量代码)
关键设计——文档不是手写的,是生成的。 所以有个配套校验 table-check:用 --dry-run 跑同样的生成,如果结果和已提交的 docs 不一致就报错(Makefile:199-214)。这保证「YAML 改了但忘了重生成文档」会被 CI 抓住。各语言 SDK 同样用 Weaver 把这份 YAML 生成本语言常量,这就是「一处定义、全栈一致」的兑现方式。
3.2 Rego 策略:构建期的兼容性闸门
光生成还不够——改约定不能破坏已经发布的契约。这由 Rego 策略(开放策略代理 OPA 的规则语言)在 make check-policies 时强制执行(Makefile:314-331)。注意:策略体系已经整体外包——绝大多数检查委托给共享仓 opentelemetry-weaver-packages(policies/README.md:3-6);本仓 policies/ 只保留上游没有的 brief.rego(要求每个属性与信号都有非空 brief,policies/brief.rego:11-25)。原先本仓的 compatibility.rego、deprecation.rego 等十余个策略文件已移除。
最关键的一行是它和谁比:
# Makefile:326-327 (check-policies 内)
--baseline-registry=https://github.com/open-telemetry/semantic-conventions/archive/refs/tags/v$(LATEST_RELEASED_SEMCONV_VERSION).zip[model]
--policy=/home/weaver/policies
它下载最新发布版当 baseline,把当前 model 和它对比。委托出去的 backwards-compatibility 包(Makefile:331)就建立在「baseline vs 当前」两套集合上做差异检查。意图很明确:稳定字段不许被删或改类型,否则下游已经依赖它的代码会崩。
策略按关切分工(policies/README.md:8-19 列出了委托清单):
| 策略包 | 把关什么 |
|---|---|
backwards-compatibility(共享包) | 向后兼容:稳定字段不许破坏性变更 |
stability(共享包) | 弃用/改名规则自洽(下一节细讲) |
naming_conventions(共享包) | 名字不许撞、类型合法、metric brief 格式 |
entity_associations(共享包) | 实体关联可解析 |
brief.rego(本仓仅存的策 略文件) | 每个属性/信号必须有非空 brief |
3.3 弃用与改名的策略自洽(stability 包)
本仓的 policies/deprecation.rego 已移除——「改名声明自洽」这条检查改由共享仓的 stability 策略包提供(policies/README.md:11-13,挂在 Makefile:329)。它检查的核心错误不变:你把字段改名了,但新名字根本不存在或也被弃用了——每条 deprecated.renamed_to 都必须指向一个真实存在、未弃用的字段。该包还顺带校验稳定实体必须有 identity、以及稳定性排序(信号的稳定性不得高于它引用的属性,除非该属性是 opt_in)。
(原版 deprecation.rego 还逐条校验改名前后的类型兼容——string→string、int→int、string → enum-of-strings 都允许,string → enum-of-ints 就拒——这批规则随文件一起移出本仓,细节以共享仓 opentelemetry-weaver-packages 为准。)
为什么重要: 弃用不是删除,而是带迁移路径的退休。策略保证每条 renamed_to 都真的指向一个可用的新家,数据迁移才不会断链。
3.4 schema 版本文件:让改名可被机器执行
策略保证「改名声明自洽」,但运行时的老数据怎么自动升级到新名字?靠 schemas/<version> 文件——每个发布版一个,记录从上一版到本版的字段映射。
看 gen_ai token 改名的真实记录:
# schemas/1.27.0:29-30 (节选)
changes:
- rename_attributes:
attribute_map:
gen_ai.usage.completion_tokens: gen_ai.usage.output_tokens
gen_ai.usage.prompt_tokens: gen_ai.usage.input_tokens
这条映射让任何遥测处理器都能把老字段 gen_ai.usage.prompt_tokens 自动重写成新字段 gen_ai.usage.input_tokens——无需改采集端代码。schema 文件按版本号目录排列,从 1.4.0 一直到 1.44.0(schemas/ 目录),构成一条完整的迁移链。
三件事如何咬合成闭环:
改 YAML(声明 deprecated.renamed_to)
│
├─▶ check-policies: stability 策略包确认新名存在且兼容
│
├─▶ table-generation: 文档同步反映改名
│
└─▶ schemas/<新版>: 写 rename_attributes,老数据可自动迁移
声明、校验、文档、迁移四步对齐,一个字段才算「合规地改了名」。
3.5 代码地图
| 主题 | 文件 | 符号/目标名 |
|---|---|---|
| Weaver 容器版本 | dependencies.Dockerfile | FROM otel/weaver:v0.25.1 |
| 文档生成 | Makefile | table-generation, registry-generation |
| 文档与 YAML 一致性校验 | Makefile | table-check(--dry-run) |
| 兼容性闸门 + baseline 对比 | Makefile | check-policies |
兼容性规则(本地 compatibility.rego 已移除,改为共享包) | Makefile | check-policies 的 backwards-compatibility 策略源 |
弃用/改名自洽规则(本地 deprecation.rego 已移除,改为共享包) | policies/README.md | stability 委托说明 |
| 版本改名映射 | schemas/1.27.0 | rename_attributes.attribute_map |