Prometheus Alertmanager 的 Elm Web UI 开发贡献指南:环境搭建、测试、格式化与本地联调实战
【免费下载链接】alertmanagerPrometheus Alertmanager项目地址: https://gitcode.com/GitHub_Trending/al/alertmanager
Alertmanager 的 Web 用户界面(ui/app)使用 Elm 语言编写,是社区开发者通过 ui/app/CONTRIBUTING.md 协作维护的核心前端模块。本文以该贡献指南为骨架,结合仓库中的 Makefile、package.json、Elm 源码、Go 静态资源服务层与 HA 示例配置,系统讲解如何搭建开发环境、运行测试与代码检查、使用elm-format统一格式、借助elm reactor实现热重载联调,以及提交前执行make build-all的完整流程,帮助你快速上手并向 Alertmanager Web UI 提交高质量的代码。
一、先了解你要贡献的模块:Elm UI 在 Alertmanager 中的位置
在动手开发之前,有必要先搞清楚ui/app在整个仓库中的角色。Alertmanager 仓库内同时维护着两套 Web UI:
ui/app:基于 Elm 0.19.1 编写的前端(本文主题),入口为 ui/app/src/Main.elm,构建产物输出到ui/app/dist/elm;ui/mantine-ui:基于 React + Mantine 的另一套界面,构建产物输出到ui/app/dist/mantine。
这两套 UI 最终都会被 Go 二进制以//go:embed方式内嵌进可执行文件:ui/web.go 第 31 行声明//go:embed app/dist,随后在Register函数中为/、/favicon.ico、/assets/*path提供 Elm UI 的静态资源(elmFS),为/ui/与/ui/assets/*path提供 Mantine UI 的资源(mantineFS)。这意味着你在ui/app里做的任何前端改动,最终会通过根 Makefile 的ui-elm目标重新构建,并被嵌入到 Alertmanager 二进制中随服务一起分发。
从源码结构看,Elm UI 的功能组织相当清晰:ui/app/src/Main.elm 是一个标准的Browser.application程序,通过 ui/app/src/Parsing.elm 解析 URL 路由,分发到告警列表、静默列表、静默表单、状态页等视图模块;ui/app/src/main.js 负责初始化 Elm 应用并通过 ports 与localStorage交互(持久化defaultCreator、groupExpandAll、firstDayOfWeek等用户偏好)。贡献者可以在这些模块上直接开展功能开发。
二、开发环境搭建:依赖安装与前置条件
贡献指南要求首先在ui/app目录下安装全部依赖,命令如下:
npm cinpm ci与npm install的区别在于它会严格按照 ui/app/package-lock.json 锁定的版本安装,保证所有贡献者在同一依赖版本下工作,避免"在我机器上能跑"的版本漂移问题。当前ui/app的关键依赖版本可从 ui/app/package.json 确认:
| 依赖 | 版本 | 用途 |
|---|---|---|
elm | 0.19.1-6 | Elm 编译器 |
elm-format | 0.8.7 | Elm 源码格式化工具 |
elm-review | 2.5.0 | Elm 静态审查(lint) |
elm-test | 0.19.1-revision6 | Elm 单元测试运行器 |
vite | ^8.0.0 | 前端构建与打包 |
vite-plugin-elm | ^3.0.1 | Vite 与 Elm 的桥接插件 |
bootstrap/font-awesome | 4.x | UI 样式库 |
Elm 语言层面的依赖(elm/browser、elm/html、elm/http、elm/json、elm/parser等)记录在 ui/app/elm.json 中,测试依赖elm-explorations/test也在此声明。
值得留意的是npm ci这条命令被封装在 ui/app/Makefile 的node_modules目标中:
node_modules: package-lock.json @echo ">> installing dependencies" $(NPM) ciMakefile 通过DOCKER变量支持两种运行方式:
- 本机直接运行(
DOCKER为空):NPM = npm、NPX = npx; - 容器内运行(
DOCKER=docker或DOCKER=podman):借助quay.io/prometheus/golang-builder基础镜像执行npm/npx,并以--user $(shell id -u):$(shell id -g)避免产生 root 属主的文件;若设置了CA_BUNDLE,还会以只读方式挂载证书到/etc/ssl/certs/ca-certificates.crt并注入NODE_EXTRA_CA_CERTS环境变量,用于代理或私有 npm 镜像场景。
另外,贡献指南建议为编辑器配置 Elm 支持(例如安装 Elm 语言插件)。编辑器配置完成后,配合下一节的elm-format保存即格式化,开发体验会非常接近 Go 社区的gofmt工作流。
三、运行测试与代码检查:make test 做了什么
贡献指南给出了测试入口:
make test这条命令背后的真实执行序列可以在 ui/app/Makefile 的test目标中看到,它并不只是跑单元测试,而是依次执行了四件事:
test: node_modules rm -rf elm-stuff/generated-code @$(NPX) elm-format $(ELM_FILES) --validate @$(NPX) elm-review @$(NPX) elm-test- 清理生成代码:删除
elm-stuff/generated-code(由 OpenAPI 代码生成产生的临时产物),确保测试在干净环境下进行; - 格式校验:
elm-format $(ELM_FILES) --validate只检查不改写,一旦发现任何源码不符合规范格式就立即失败——这是把"提交的 Elm 代码必须经过elm-format"这条硬性要求自动化了。ELM_FILES变量通过find src -iname *.elm动态收集所有 Elm 源文件(Makefile 特意使用=惰性展开,因为源码文件在构建过程中会变化); - 静态审查:
elm-review执行仓库配置的审查规则集,对应 ui/app/review/elm.json 中的elm-review、elm-review-simplify、elm-review-unused等依赖,可检测未使用的导入、可简化的表达式等代码质量问题; - 运行单元测试:
elm-test执行 ui/app/tests 目录下的测试套件。
测试还支持输出 JUnit 报告以对接 CI,只需在调用时传入JUNIT_DIR变量:
make test JUNIT_DIR=build/test-results此时elm-test会以--report=junit模式运行,并把结果写入指定目录的junit.xml文件中。
仓库中的测试用例颇具参考价值,例如 ui/app/tests/Filter.elm 使用describe/test与fuzz对标签匹配器的解析、URL 序列化、字符串转义做了大量覆盖,包括带点号与连字符的标签名、UTF-8 标签名、对 NBSP(不换行空格)的拒绝、引号和反斜杠的转义还原等边界情况。新增或修改 ui/app/src/Utils/Filter.elm 这类核心工具模块时,应当同步补充对应测试。
四、代码格式化:elm-format 是强制要求
贡献指南强调:"所有提交的 Elm 代码必须使用elm-format格式化"。这是仓库的硬性门槛,理由是 Elm 社区与 Go 社区一样认同"统一的机器格式能消除无谓的格式争论,让 Code Review 聚焦于逻辑本身"。
使用方式非常灵活:
- 保存时自动格式化:在编辑器(VS Code、IntelliJ 等)中安装 Elm 插件并开启 format-on-save,类似许多 Go 开发者使用
gofmt的方式; - 命令行手动执行:直接运行
elm-format针对单个文件或目录; - Make 目标批量格式化:仓库提供了便捷入口,贡献指南中注释掉的命令即为此意:
# make formatui/app/Makefile 中的format目标实现为:
format: node_modules $(ELM_FILES) @echo ">> format front-end code" @$(NPX) elm-format --yes $(ELM_FILES)它会遍历src下全部 Elm 文件并执行elm-format --yes(自动确认覆盖)。需要注意的是,make test中的--validate模式只校验不修改,所以推荐工作流是:先用make format(或编辑器保存时格式化)整理代码,再运行make test验证格式合规、审查与测试全部通过。
五、Elm 学习资源:从零上手所需的知识准备
贡献指南针对不熟悉 Elm 的开发者整理了一份学习路径(原指南附带的在线资源链接在此仅作文字说明,建议自行检索):
- 官方 Elm 指南:约一小时的完整通读即可对语言核心有整体认识,之后可以借助 Elm 编译器的类型错误提示边写边学,直接开始编写功能代码;
- 语法参考:写作时遇到记不清的语法细节随时查阅;
- 官方代码风格指南:了解 Elm 社区推荐的命名与组织惯例;
- Elm Conf 演讲视频:观看社区最新实践与案例;
- Elm 调试器:Elm 自带出色的时间旅行调试器,是理解应用状态流转的利器——贡献者反馈在排查 UI 行为问题时该工具价值极大。
Elm 是一种强类型、纯函数式、编译到 JavaScript 的语言,其"编译通过即大概率可运行"的特性与"编译器是最好的老师"的开发体验,是维护 Alertmanager 前端长期稳定性的重要保障。如果你此前只有 JavaScript/TypeScript 经验,可以先从 ui/app/src/Utils/Filter.elm(纯函数、无副作用、易测试)这类模块入手,再逐步接触 ui/app/src/Updates.elm 这类涉及消息分发与副作用调度的模块。
六、本地开发工作流:与真实 Alertmanager 联调
6.1 准备后端:按 HA 模式启动 Alertmanager
贡献指南要求先按仓库顶层的 HA(高可用)Alertmanager 说明编译并运行后端。仓库提供了现成的工具链:
在仓库根目录编译二进制(根 Makefile 的
build目标会同时构建前后端,也可只执行go build ./cmd/alertmanager之类的常用命令);使用
goreman按 Procfile 一键拉起多实例集群。Procfile 定义了 4 个进程:a1:监听:9093,集群地址127.0.0.1:8001,作为集群首节点;a2:监听:9094,集群地址127.0.0.1:8002,通过--cluster.peer=127.0.0.1:8001加入集群;a3:监听:9095,集群地址127.0.0.1:8003,同样以a1为对等节点;wh:运行 examples/webhook/echo.go 作为告警接收端回显服务;
三者共用 examples/ha/alertmanager.yml 配置,该配置演示了
group_by: ['alertname']、group_wait: 30s、group_interval: 5m、repeat_interval: 1h的分组与重复策略,以及一条"critical 抑制 warning"的inhibit_rules规则,并把 webhook 接收端指向http://127.0.0.1:5001/;用 examples/ha/send_alerts.sh 向
a1、a2、a3三个实例的/api/v1/alerts批量投递 6 条DiskRunningFull示例告警(包含不同dev、instance组合以及 critical/warning 严重级别),用于验证 UI 的告警展示、分组与抑制效果。
6.2 启动前端开发服务器:make dev-server
后端就绪后,进入ui/app启动开发服务器:
# cd ui/app # make dev-servermake dev-server其底层实现(ui/app/Makefile)是npx elm reactor(容器模式下会以-p 8000:8000端口映射方式在镜像内运行同样命令)。启动后应用默认运行在http://localhost:8000(容器方式同样暴露 8000 端口),开发服务器会监听文件系统变化,任何源码修改都会触发自动重新编译,刷新浏览器即可看到效果,无需手动重启。
打开 ui/app/src/Main.elm 即可开始编辑。理解开发/生产环境差异对联调至关重要,见 ui/app/src/Main.elm 第 77-89 行的初始化逻辑:
production标志来自 ui/app/src/main.js 注入的flags(开发时为false);- 非生产模式下,API 地址固定为
http://localhost:9093/(对应a1实例的监听端口),静态资源根为/; - 生产模式下,API 地址与资源根取自当前 URL 路径,这正是 ui/app/vite.config.mjs 中
base: "./"配置的用途——保证部署在--web.route.prefix自定义路径前缀下时资源相对引用依然正确。
七、提交变更前的最后一步:make build-all
贡献指南明确要求:提交代码前必须在仓库根目录执行make build-all。根 Makefile 中该目标的定义是:
build-all: assets apiv2 build展开来看,它串起了完整的前后端构建链:
assets目标生成 OpenAPI 派生的 Elm 数据模块、构建两套 UI、生成邮件模板;apiv2目标通过 scripts/swagger.sh 从 api/v2/openapi.yaml 生成 v2 API 的 models/restapi/client 代码;build目标依次执行ui-elm(进入ui/app执行make build)、ui-mantine与common-build。
而ui/app的build目标(见 ui/app/Makefile)实际执行的是npm run build(即vite build),产物输出到ui/app/dist/elm,再由 ui/web.go 的//go:embed app/dist内嵌进二进制。Vite 配置还启用了 gzip(level 9)与 brotli 压缩,并配合 ui/web.go 中基于Accept-Encoding的内容协商逻辑提供预压缩资源,immutable资源(/assets/*下的文件)会获得Cache-Control: public, max-age=31536000, immutable长缓存头。
执行make build-all的意义在于:它不仅验证 Elm 源码能否编译通过、前端能否打包成功,还验证了代码生成、Go 编译与资源嵌入的整条链路,确保你的改动不会破坏任何一环。这是提交 PR 前最稳妥的自检方式。
八、从源码出发的进阶建议
若想深入参与 Elm UI 的开发,建议沿着以下源码路径建立整体认知:
- 入口与启动:ui/app/src/main.js →
Elm.Main.init注入 flags(production、firstDayOfWeek、defaultCreator、groupExpandAll),并订阅三个 ports 实现 localStorage 持久化; - 路由与页面组织:ui/app/src/Main.elm 将 URL 解析为
AlertsRoute、SilenceListRoute、SilenceViewRoute、SilenceFormNewRoute/SilenceFormEditRoute、StatusRoute、SettingsRoute等路由,分别对应 ui/app/src/Views/AlertList、ui/app/src/Views/SilenceList、ui/app/src/Views/SilenceForm、ui/app/src/Views/Status 等视图目录(每个目录下均按Types/Updates/Views三件套组织); - API 数据层:
src/Data目录由 OpenAPI 生成器从 api/v2/openapi.yaml 自动生成(make src/Data目标,基于openapitools/openapi-generator-cli容器),涉及 API 契约变更时应重新生成而不是手改; - 过滤与匹配逻辑:ui/app/src/Utils/Filter.elm 实现与 PromQL 一致的标签匹配器语法,支持
=、!=、=~、!~四种操作符(详见 ui/app/README.md 的过滤说明与 ui/app/tests/Filter.elm 的测试覆盖)。
九、常见问题速查
make test报格式校验失败:先执行make format(或编辑器保存时格式化),再重新运行make test;elm-review报未使用代码或可简化表达式:可运行make review(即elm-review --fix)自动修复一部分问题,其余按提示手工处理;- 依赖安装受网络/代理影响:使用
DOCKER=docker make test将 npm 执行迁移到容器内,必要时配合CA_BUNDLE挂载企业 CA 证书; - API 数据模块缺失:
src/Data是生成产物,若缺失或过期,运行make src/Data(或根目录make assets)重新生成; - 想快速验证单页效果:无需启动完整后端,运行
npx elm reactor后直接访问对应.elm文件即可获得 Elm 自带的调试页面,但完整功能联调仍需按第六节启动后端。
按照以上流程完成环境搭建、测试、格式化与构建验证后,你的改动就具备了合并到 Alertmanager 主线的条件。相关参考文件汇总:ui/app/CONTRIBUTING.md、ui/app/Makefile、ui/app/package.json、ui/app/elm.json、ui/app/vite.config.mjs、ui/web.go、Procfile、examples/ha/alertmanager.yml、examples/ha/send_alerts.sh。
【免费下载链接】alertmanagerPrometheus Alertmanager项目地址: https://gitcode.com/GitHub_Trending/al/alertmanager
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考