ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Jaeger 项目贡献指南:从开发环境搭建到 Feature Gate 治理的完整实践

Jaeger 项目贡献指南:从开发环境搭建到 Feature Gate 治理的完整实践 Jaeger 项目贡献指南从开发环境搭建到 Feature Gate 治理的完整实践【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger本文以 JaegerCNCF 分布式追踪平台仓库根目录下的 CONTRIBUTING.md 为主线系统讲解从克隆源码、搭建开发环境、通过 CI 检查到提交 Pull Request 的完整贡献流程并深入剖析该项目的 Go 版本升级机制、CLI 标志废弃流程与 Feature Gate 治理约定。读者学完后将能独立完成 Jaeger 的本地构建、测试与代码提交并理解其演进类变更升级 Go、废弃标志、引入破坏性行为是如何在工程化层面被规范化管理的。概览Jaeger 的贡献模型Jaeger 采用 Apache 2.0 许可证通过 GitHub Pull Request 接受代码与文档贡献。围绕贡献流程仓库在根目录维护了一套配套文档体系CONTRIBUTING_GUIDELINES.md通用贡献规范AI_POLICY.md使用 AI 工具辅助贡献时的使用策略CODE_OF_CONDUCT.md社区行为准则DCO开发者来源认证Developer Certificate of Origin签署说明CHANGELOG.md变更日志废弃与破坏性变更必须在此登记。贡献流程的硬性前提是所有提交必须经过 DCO 签名检查且新功能必须携带测试——这两点在后面的代码提交条件与测试指南两节会展开说明。开发环境搭建前置条件安装 Go 并配置GOPATH将$GOPATH/bin加入PATH。仓库使用 Go Modules 管理依赖当前主模块声明的 Go 版本见 go.modgo 1.27.0。在 macOS 上运行make test等 Makefile 目标时必须安装 GNUsed因为 Makefile 中的行内替换语法依赖 GNU 扩展安装命令为brew install gnu-sed这一要求在 Makefile 中有对应实现它通过$(shell GOOS $(GO) env GOOS)检测宿主机系统在 darwin 上将SED变量设置为gsed其余平台使用sed。克隆与初始化git clone gitgithub.com:jaegertracing/jaeger.git jaeger cd jaeger # 初始化 jaeger-ui 等 git 子模块 git submodule update --init --recursive # 安装构建与测试所需工具 make install-tools # 运行全部单元测试 make testmake install-tools依赖 scripts/makefiles/Tools.mk 中定义的install-tools目标它会根据 internal/tools/tools.go 中的工具清单将gofumpt、golangci-lint、gotestsum、govulncheck、mockery、ocbOpenTelemetry Collector Builder等工具安装到.tools目录。仓库中的idl/与jaeger-ui/均为 git 子模块分别对应 jaeger-idl 与 jaeger-ui 上游仓库因此在当前 checkout 中它们显示为空目录需要执行git submodule update --init --recursive拉取内容。本地运行带 UI 的 Jaegergo run ./cmd/jaeger --config ./cmd/jaeger/config.yaml该命令的作用机制如下Jaeger v2 主二进制位于 cmd/jaeger是一个整合了 collector、query 与 ingester 的全功能单体默认配置 cmd/jaeger/config.yaml 通过jaeger_query扩展源码位于 cmd/jaeger/internal/extension/jaegerquery挂载 UIUI 资源来自jaeger-ui子模块需先执行make build-ui编译默认从最新 UI release 下载构建产物也可以从源码构建需要 Node.js 24。项目结构从目录布局理解架构CONTRIBUTING.md 给出了清晰的顶层目录语义结合当前仓库验证如下github.com/jaegertracing/jaeger cmd/ - 所有二进制入口 jaeger/ - Jaeger v2 主二进制整合 collector、query、ingester anonymizer/ - 从 Jaeger query 匿名化 trace 并保存到文件的工具 tracegen/ - 生成稳定流量简单 trace 的工具 es-index-cleaner/ - 清理 Elasticsearch 旧索引的工具 es-rollover/ - 管理 Elasticsearch 索引的工具 esmapping-generator/ - 生成 Elasticsearch mapping 的工具 remote-storage/ - 通过 Remote Storage API v2 共享单节点存储实现 examples/ grafana-integration/ - 结合 Jaeger、Grafana、Loki、Prometheus 的演示应用 hotrod/ - 演示追踪埋点的示例应用 otel-demo/ - 使用 OpenTelemetry Collector 与 Jaeger 的演示应用 docker-compose/ - 模拟不同 Jaeger 部署形态的 docker-compose 配方 monitor/ - 服务性能监控SPM开发/演示环境 internal/ - 构成 Jaeger 的内部模块 storage/ metricstore/ - 指标存储接口与实现Prometheus、Elasticsearch 等 v1/ - Trace 存储 v1 接口与实现Cassandra、Elasticsearch、Badger 等 v2/ - Trace 存储 v2 接口与实现gRPC、ClickHouse 等 monitoring/ - 监控资产如 jaeger-mixin 的 Grafana dashboard 生成器 ports/ - 集中式端口定义 scripts/ - 各类项目脚本CI、license 更新等 go.mod - Go 模块依赖跟踪文件 Makefile - 自动化构建、测试与部署的配方定义以cmd/jaeger为例其内部进一步划分为components/组件注册、jaegercli/CLI 入口与internal/extension、exporter、processor 等私有实现体现了 v2 版本基于 OpenTelemetry Collector 组件模型的架构。代码提交条件与工作流提交 PR 前必须满足以下条件使用 fork 中的命名分支不能直接使用main分支否则 CI 任务会失败且无法合并PR 中所有 commit 必须签名由 GitHub 上的 DCO 检查验证DCO 文件说明了签署机制提交前依次运行make fmt # 提交所有自动格式化产生的改动 make lint make test其中make test在 Makefile 中的实现为通过gotestsum运行go test -race并附带memory_storage_integration构建标签执行全量测试test: $(GOTESTSUM) $(GOTESTSUM) $(GOTESTSUM_FLAGS) -- $(RACE) -tagsmemory_storage_integration ./...注意在s390x架构上go test不支持-raceMakefile 已通过RACE变量自动处理该差异。自动格式化gofumpt 与 import 分组项目使用gofumpt作为格式化工具它由make install-tools随golangci-lint一并安装。建议在 IDE 中配置保存时自动执行gofumpt例如 VSCode 的settings.jsongo.formatTool: gofumpt, gopls: { formatting.gofumpt: true, }同时项目对 Go 文件 import 分组有明确约定顺序为标准库 → 第三方项目 → jaeger 项目自身各组之间以空行分隔import ( fmt github.com/uber/jaeger-lib/metrics go.uber.org/zap github.com/jaegertracing/jaeger/cmd/agent/app github.com/jaegertracing/jaeger/cmd/collector/app/builder )这一约定由 scripts/lint/import-order-cleanup.py 强制校验make lint中的lint-imports子目标make fmt会以 inplace 模式自动修复 import 顺序。lint 流水线make lint是一个复合目标包含多个子检查见 Makefile 的lint定义lint-fmt校验全部 Go 源文件已按 gofmt gofumpt 格式化lint-license校验所有跟踪文件带有 license 头scripts/lint/updateLicense.pylint-imports校验 import 分组顺序lint-semconv校验 OpenTelemetry 语义约定版本scripts/lint/check-semconv-version.shlint-goversion校验 Go 版本一致性详见下文lint-goleak校验所有含测试的包在TestMain中调用 goleakscripts/lint/check-goleak-files.shlint-go运行golangci-lint.golangci.yml并为每个 checkout 使用独立缓存lint-monitoring校验 Grafana dashboard JSON 与生成器输出一致lint-line-endings校验 Unix 行尾、无尾随空白、EOF 以换行结尾scripts/lint/check-line-endings.py。此外还有govulncheck目标运行 internal/tools/tools.go 中声明的govulncheck ./...以及lint-nocommit阻止包含nocommit字符串的 PR。测试指南95% 覆盖率门槛与 .nocover 机制项目的测试策略核心是所有新功能必须包含测试Bug 修复应包含回归测试没有充分测试覆盖的 PR 不会被合并。仓库当前的覆盖率门槛设定为 95%。无测试包的强制检查由于go test不会为没有测试文件的包生成覆盖率信息项目通过make nocover构建步骤来阻断这类情况。该目标调用 scripts/lint/check-test-files.sh对每个包含 Go 文件的目录检查是否存在*_test.go。若发现缺失会报出如下错误error: at least one *_test.go file must be in all directories with go files so that they are counted for code coverage. If no tests are possible for a package (e.g. it only defines types), create empty_test.go因此所有包都必须至少有一个*_test.go文件若某个包确实无法测试例如仅定义类型则应创建empty_test.go。从脚本源码看main.go所在的包即package main是唯一豁免因为它不属于可测试的库代码。仓库根目录与各子目录中的大量empty_test.go文件正是这一策略的落地证据。排除无法测试的包.nocover 文件对于需要外部依赖才能测试的场景例如需要连接 Cassandra 才能创建gocql.Session的函数约定是将这类函数隔离到独立包中并添加.nocover文件将该包从覆盖率计算中排除。文件内容必须写明排除原因例如$ cat ./pkg/cassandra/config/.nocover requires connection to Cassandracheck-test-files.sh 在发现.nocover文件时会输出被排除的包及其原因若.nocover为空未写明原因脚本会直接报错退出。Code Review 与合并要求审查人检查清单Jaeger 的变更通过 GitHub Pull Request 审查审查人需要评估变更是否适合项目、实现是否正确可维护、是否配有合适的测试与文档。批准 PR 前需确认变更可理解、范围限定于所描述的问题并与项目架构和编码风格一致新行为有测试Bug 修复在可行时包含回归覆盖且必要的 CI 检查全部通过涉及安全、依赖变更、认证/授权、网络暴露行为、发布工具链与配置默认值的改动需要相关领域维护者的额外审查生成文件不得手工编辑贡献者必须更新源定义并用文档化的目标重新生成PR 标题与提交历史适合项目的 squash-merge 工作流。非平凡的 PR 必须由除作者外的维护者或有经验的贡献者审查通过后才能合并纯文档、拼写、格式或机械性跟进变更在风险低且 CI 通过的前提下可由维护者直接合并。维护者合并流程合并前确保 PR 标题具有描述性并遵循 CONTRIBUTING_GUIDELINES.md 中良好的提交信息规范使用 GitHub 的Squash and merge选项合并避免产生 merge commit合并后关闭关联的 issue。升级 Go 版本一处声明、全仓同步Jaeger 始终使用最新的 Go 次版本minor release构建当前为 Go 1.27见 go.mod 与 .golangci.yml 的go: 1.27。Go 版本以顶层go.mod为唯一事实来源并镜像到其他go.mod、.golangci.yml以及共享的.github/actions/setup-goaction 中。CI 只通过 .github/actions/setup-go/action.yml 安装 Go其中硬编码go-version: 1.27.x工作流本身不声明任何 Go 版本。scripts/lint/check-go-version.sh 作为make lint的一部分运行当任何副本与顶层go.mod不一致时会使构建失败。值得注意的是该脚本不再从远端抓取最新 Go 版本而是直接以顶层go.mod声明的版本为基准避免新版本发布引发 CI 循环依赖。升级操作步骤手工修改顶层go.mod例如go mod edit -go1.27.0。脚本从该文件读取目标版本因此其他文件必须等这一步完成才能更新运行./scripts/lint/check-go-version.sh -u将版本传播到所有其他位置加-v可打印每个被重写文件的 diff运行make fmt、make lint、make test修复新编译器与新 linter 报告的问题为新的 Go 版本升级 Delve。dlv拒绝附加到由比它更新的 Go 构建的二进制而 all-in-one 集成测试会运行 debug 镜像因此跳过这一步会导致 CI 失败。镜像发布后要么将scripts/build/docker/debug/Dockerfile重新指向它要么交给 Renovate 机器人管理版本 pin。脚本的-u模式只重写次版本号若某一行固定了 patch 版本脚本会报告该行并退出要求手工更新。另外idl子模块拥有自己的go.mod且被刻意排除在同步范围之外脚本中有if [[ $file ./idl/go.mod ]]跳过逻辑其 Go 版本通过向 jaeger-idl 仓库提交 PR 来升级。废弃 CLI 标志的完整生命周期Jaeger 对 CLI 标志的废弃有严格的时间表与代码约定时间线标志在 release N 中废弃最早在 release N2 或三个月后以较晚者为准移除废弃提示添加废弃前缀时通过提示信息说明该标志未来可能被移除例如(deprecated, will be removed after 2020-03-15 or in release v1.19.0, whichever is later)常量定义在定义标志的文件顶部添加常量和注释例如// TODO deprecated flag to be removed healthCheckHTTPPortWarning (deprecated, will be removed after 2020-03-15 or in release v1.19.0, whichever is later)复用常量将该常量作为帮助文本的前缀例如flagSet.Int(healthCheckHTTPPort, 0, healthCheckHTTPPortWarning see --adminHTTPHostPort)解析时告警在把废弃标志解析进配置时用相同的废弃信息记录一条 warning隔离处理在initFromViper函数中妥善处理废弃标志不要将它们传给业务函数。移除废弃标志确保代码中对标志变量的所有引用已被删除在 CHANGELOG.md 中添加 Breaking Changes 条目说明移除了哪个标志、应该改用哪个标志例如* Remove deprecated flags --old-flag, please use --new-flag (#1234, [myusername](https://github.com/myusername))Feature Gate管理破坏性变更的标准化流程对于可能构成破坏性变更的行为修改Jaeger 尽可能使用 OTel Collector 的 feature gate 机制Jaeger 与内嵌的 Collector 共享进程级的 OTelfeaturegate.GlobalRegistry()。典型工作流如下引入名为jaeger.***的新 feature gate若不希望立即改变默认行为以Alpha状态启动默认禁用无需在 changelog 中标注破坏性变更若希望立即改变默认行为以Beta状态启动默认启用但用户仍可关闭并在 changelog 中标注破坏性变更两个版本后晋升为Stable不仅默认启用尝试禁用还会产生运行时错误旧行为代码应被删除同时标注破坏性变更再两个版本后移除无用的 feature gate并标注破坏性变更。Jaeger Feature Gate 的命名与生命周期约定命名每个新 gate ID 必须使用jaeger.前缀例如jaeger.es.config.rejectLegacyRotationFlags以避免与内嵌 Collector 及其 contrib 组件的 gate 产生 ID 冲突。早于该约定的遗留 ID如storage.clickhouse可在废弃/移除窗口期内无前缀注册但不得作为新工作的正式 ID应引入带jaeger.前缀的名字并将旧 ID 视为废弃别名FromVersion记录引入版本而非当前阶段WithRegisterFromVersion设置为 gate ID 首次加入的 release后续阶段晋升时不修改它ToVersion是移除版本gate 进入 Stable 或 Deprecated 后必须提供否则注册时会 panic它指明 gate ID 被移除的 release。Stable gate 不能再被禁用显式启用会记录一条将在ToVersion中移除的日志重命名 gate 本身就是破坏性变更gate ID 是用户可见配置--feature-gatesidOTel API 没有内置 ID 别名因此重命名需要走废弃周期注册新 ID并通过internal/featuregate.RenamedGate让旧 ID 在窗口期内作为废弃别名继续工作之后在后续 release 移除旧 ID。RenamedGate只支持 Alpha 和 Beta因此被重命名的 gate 必须先移除遗留别名才能晋升 Stable。源码印证RenamedGate 的实现internal/featuregate/renamed.go 给出了RenamedGate的具体实现其中有两个关键设计构造时校验新旧 gate必须处于相同阶段且只能是 Alpha 或 Beta否则直接 panicIsEnabled()的计算语义分阶段而异Alpha默认禁用用 OR 合并任一 ID 被启用即生效Beta默认启用用 AND 合并只有新旧 ID 同时启用才生效用户可通过显式关闭旧 ID 表达不使用新行为当用户选择了遗留 ID 时会通过sync.Once向 stderr 输出一次重命名告警。仓库中的真实注册示例见 internal/storage/elasticsearch/config/config_legacy.gojaeger.es.config.rejectLegacyRotationFlagsv2.21.0 引入Beta与遗留别名es.config.rejectLegacyRotationFlagsv2.9.0 引入通过NewRenamedGate绑定启用后继续使用use_aliases、use_ilm、span_read_alias等废弃 ES 轮转标志将从弃用警告升级为校验错误。另一个示例 internal/storage/v2/clickhouse/factory.go 展示了 Stable gate 的正确用法jaeger.clickhouse与其废弃别名storage.clickhouse均注册为 Stable并声明WithRegisterFromVersion与WithRegisterToVersion(v2.23.0)——ClickHouse 始终可作为存储后端这些 gate 只是为了让存量--feature-gates参数继续生效作为 no-op直到被移除。用户视角的命令行交互jaegercli提供了独立的 featuregate 子命令实现见 cmd/jaeger/jaegercli从 OTel Collector 命令树中提取jaeger featuregate jaeger featuregate --help该命令基于 OTel Collector 的featuregate命令实现cmd/internal/featuregate/command.go 中通过otelcol.NewCommand构造并摘取featuregate子命令用于在运行时查询所有已注册 gate 的 ID、阶段、引入/移除版本等元数据。对应的测试 cmd/internal/featuregate/command_test.go 验证了命令的使用形式为featuregate [feature-id]。结语将流程规范沉淀为可验证的自动化纵观 Jaeger 的贡献体系其核心特征是把看似主观的工程规范格式化、测试覆盖、版本同步、废弃节奏转化为可自动化、可验证的构建目标与 CI 检查make fmt与make lint覆盖格式与静态检查make nocover与check-test-files.sh守住测试覆盖底线check-go-version.sh保证 Go 版本单一事实来源Feature Gate 约定则让破坏性变更拥有可预测、可回退、可追踪的发布路径。对贡献者而言遵循 CONTRIBUTING.md 及其引用的配套文档本质上就是跟随一套已经被 CI 强校验的工程方法论。【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进