Gitea 监控 Mixin 实战:从内置 Metrics 指标生成可配置的 Grafana 仪表盘
Gitea 仓库自带一套 Prometheus 指标端点,而 contrib/grafana-monitoring-mixin/README.md 讲解的正是如何基于这些指标,用 Jsonnet + Grafonnet 工具链生成一组可配置的 Grafana 仪表盘。读完本文,你将掌握:Gitea 端 [metrics] 配置项的开启方式、jb/jsonnet/mixtool 等工具的安装、make 构建流程的每一步在做什么,以及 config.libsonnet 中每个可定制参数(仪表盘命名、刷新频率、Issue 分仓/分标签图、标签配色)如何影响最终导入 Grafana 的 JSON 文件。
一、Mixin 的定位与目录结构
所谓 "mixin",是 Prometheus 社区监控生态中的一种约定:用代码(这里是 Jsonnet)声明式地描述一套仪表盘与告警规则,通过构建工具生成 Grafana 可直接导入的 JSON。Gitea 的 Mixin 位于 contrib/grafana-monitoring-mixin/ 目录,其定位是基于 Gitea 内置 metrics 端点导出的指标构建仪表盘,而不是自己采集。
目录职责如下:
| 文件/目录 | 作用 |
|---|---|
| contrib/grafana-monitoring-mixin/Makefile | 构建入口,定义 vendor、build、fmt、lint、dashboards_out、clean 等目标 |
| contrib/grafana-monitoring-mixin/mixin.libsonnet | Mixin 主入口,把仪表盘定义与用户配置两个 Jsonnet 对象合并 |
| contrib/grafana-monitoring-mixin/config.libsonnet | 用户可编辑的配置项(命名、标签、刷新周期、要展示的指标、标签配色等) |
| contrib/grafana-monitoring-mixin/dashboards/overview.libsonnet | "Gitea Overview" 仪表盘的全部面板定义 |
| contrib/grafana-monitoring-mixin/dashboards/dashboards.libsonnet | 仪表盘聚合层,当前转发到 overview |
| contrib/grafana-monitoring-mixin/lib/dashboards.jsonnet | 构建入口脚本,遍历 grafanaDashboards 对象生成多个 JSON 文件 |
| contrib/grafana-monitoring-mixin/lib/alerts.jsonnet、contrib/grafana-monitoring-mixin/lib/rules.jsonnet | Prometheus 告警与规则 YAML 的脚手架(见第六节说明) |
| contrib/grafana-monitoring-mixin/jsonnetfile.json | jsonnet-bundler 依赖声明 |
从 jsonnetfile.json 可以看到唯一的依赖是 Grafana 官方维护的 grafonnet-lib(子目录 grafonnet),版本锁定在 master;具体的锁版本记录在 jsonnetfile.lock.json 中,由 jb install 拉取到 vendor/ 目录供 jsonnet 通过 -J vendor 查找导入。
mixin.libsonnet 本身只有一行逻辑:
(import 'dashboards/dashboards.libsonnet') +
(import 'config.libsonnet')
即把"仪表盘定义"与"用户配置"两个对象相加合并。仪表盘一侧通过 grafanaDashboards+:: 字段暴露面板,配置一侧通过 _config+:: 字段暴露参数,二者互不冲突,合并后供构建脚本按需取值。
二、前置条件:开启 Gitea 的 Metrics 端点
Mixin 消费的全部指标都来自 Gitea 自带的 /metrics 端点,因此部署侧必须先开启。参考 custom/conf/app.example.ini 中 [metrics] 段的官方注释:
;[metrics]
;; Enables metrics endpoint. True or false; default is false.
;ENABLED = false
;; If you want to add authorization, specify a token here
;TOKEN =
;; Enable issue by label metrics; default is false
;ENABLED_ISSUE_BY_LABEL = false
;; Enable issue by repository metrics; default is false
;ENABLED_ISSUE_BY_REPOSITORY = false
这 4 个配置项与源码的对应关系可以在 modules/setting/metrics.go 中得到印证:
var Metrics = struct {
Enabled bool
Token string
EnabledIssueByLabel bool
EnabledIssueByRepository bool
}{
Enabled: false,
Token: "",
EnabledIssueByLabel: false,
EnabledIssueByRepository: false,
}
即全部默认关闭:不配置时 /metrics 端点不启用,Prometheus 抓不到任何 gitea_ 前缀的指标,仪表盘自然一片空白。
指标本身的实现位于 modules/metrics/collector.go,namespace 常量定义为 "gitea_",Collector 结构体逐一定义了 gitea_organizations、gitea_users、gitea_teams、gitea_repositories、gitea_milestones、gitea_stars、gitea_releases、gitea_issues、gitea_issues_open、gitea_issues_closed、gitea_issues_by_label、gitea_issues_by_repository 等描述符。Mixin 中引用的每一个指标名都必须能在该 Collector(或标准 Go/进程指标如 process_*)中找到来源,这一点后文逐面板核对。
注意一个历史前提:README 中提到 gitea_issues_by_repository / gitea_issues_by_label 两个指标"Requires Gitea 1.16.0 with … set to true"。在当前仓库代码中,这两个描述符已直接内建于 Collector,且分别受 ENABLED_ISSUE_BY_LABEL、ENABLED_ISSUE_BY_REPOSITORY 两个开关控制,标签维度形如 gitea_issues_by_label{label="bug"},仓库维度形如 gitea_issues_by_repository{repository="org/repo"}——这正与 config.libsonnet 中注释给出的指标样例一致。
三、安装构建工具
按 contrib/grafana-monitoring-mixin/README.md 的步骤,需要安装两类工具:
# 依赖拉取 + 渲染核心(必需)
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
# 或用 Homebrew: brew install go-jsonnet
# 校验与格式化(可选,但有 Go 环境时装一下最方便)
go install github.com/monitoring-mixins/mixtool/cmd/mixtool@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
各工具在构建流程中的分工:
jb:读取 jsonnetfile.json,把grafonnet-lib依赖下载到vendor/(对应 Makefile 的vendor目标);jsonnet:把 Jsonnet 源文件求值、manifest 成 Grafana JSON(对应dashboards_out目标);mixtool:mixin 项目的官方校验器,用于检查 mixin 结构是否符合约定(make lint中执行mixtool lint mixin.libsonnet);jsonnetfmt:Jsonnet 格式化器,保证源码风格统一(make fmt/make lint)。
四、构建流程:make 到底做了什么
构建命令只有一条:
make
对照 Makefile 逐目标拆解:
JSONNET_FMT := jsonnetfmt -n 2 --max-blank-lines 1 --string-style s --comment-style s
all: build dashboards_out
vendor: jsonnetfile.json
jb install
build: vendor
dashboards_out: mixin.libsonnet config.libsonnet $(wildcard dashboards/*)
@mkdir -p dashboards_out
jsonnet -J vendor -m dashboards_out lib/dashboards.jsonnet
clean:
rm -rf dashboards_out
-
vendor:执行jb install,依据jsonnetfile.json拉取grafonnet-lib到vendor/。注意该目标依赖jsonnetfile.json这一文件,只有它变动才会重新执行——锁文件jsonnetfile.lock.json保证依赖版本可复现。 -
dashboards_out(默认目标all的实质工作):jsonnet -J vendor -m dashboards_out lib/dashboards.jsonnet-J vendor:把vendor/加入导入搜索路径,这样 overview.libsonnet 第一行的import 'github.com/grafana/grafonnet-lib/grafonnet/grafana.libsonnet'才能解析;-m dashboards_out:把顶层对象的每个字段分别输出为dashboards_out/<字段名>文件。
-
fmt/lint:前者用jsonnetfmt -i原地格式化全部*.libsonnet/*.jsonnet(跳过 vendor);后者用diff方式检查格式化差异,并额外跑mixtool lint mixin.libsonnet校验 mixin 规范。 -
clean:删除dashboards_out目录。
构建入口 lib/dashboards.jsonnet 只有 5 行:
local dashboards = (import '../mixin.libsonnet').grafanaDashboards;
{
[name]: dashboards[name]
for name in std.objectFields(dashboards)
}
它从合并对象中取出 grafanaDashboards,再对每个仪表盘名(当前是 gitea-overview.json)逐个输出。因此最终产物是 dashboards_out/gitea-overview.json,需要导入 Grafana。README 提醒:导入方式取决于你的环境(Grafana 界面导入、provisioning 目录、API 等),Mixin 本身只负责生成 JSON。
五、config.libsonnet:可配置项逐项解析
mixin.libsonnet 合并的配置一侧就是 config.libsonnet 的 _config 字段,它是唯一需要用户编辑的文件。逐项说明:
| 字段 | 默认值 | 作用 |
|---|---|---|
dashboardNamePrefix |
'Gitea' |
仪表盘标题前缀,最终标题为 '%s Overview' % prefix(即 "Gitea Overview") |
dashboardTags |
['gitea'] |
写入仪表盘 tags,便于在 Grafana 中按标签检索 |
dashboardPeriod |
'now-1h' |
仪表盘 time_from,即打开时的默认时间窗口 |
dashboardTimezone |
'default' |
时区设置 |
dashboardRefresh |
'1m' |
自动刷新间隔 |
showIssuesByRepository |
true |
是否渲染 "Issues by repository" 面板;依赖 ENABLED_ISSUE_BY_REPOSITORY = true |
showIssuesByLabel |
true |
是否渲染 "Issues by label" 面板;依赖 ENABLED_ISSUE_BY_LABEL = true |
showIssuesOpenClose |
true |
true 时 Gitea stats 展示 gitea_issues_open/gitea_issues_closed 两个指标;false 时退化为单个 gitea_issues |
giteaStatMetrics |
见下文 | Gitea stats 统计面板与 Changes 变化图使用的指标列表,可按需增删 |
issueLabels |
见下文 | Issue 标签 → 颜色的映射,用于图上按标签着色 |
giteaStatMetrics 的默认列表为:
[
{ name: 'gitea_organizations', description: 'Organizations' },
{ name: 'gitea_teams', description: 'Teams' },
{ name: 'gitea_users', description: 'Users' },
{ name: 'gitea_repositories', description: 'Repositories' },
{ name: 'gitea_milestones', description: 'Milestones' },
{ name: 'gitea_stars', description: 'Stars' },
{ name: 'gitea_releases', description: 'Releases' },
]
+ if c.showIssuesOpenClose then
[
{ name: 'gitea_issues_open', description: 'Issues opened' },
{ name: 'gitea_issues_closed', description: 'Issues closed' },
] else
[
{ name: 'gitea_issues', description: 'Issues' },
]
注意两个机制:name 即 Prometheus 指标名(description 只用于面板图例/文案);列表通过 Jsonnet 的对象字段拼接 + 做动态组合——showIssuesOpenClose 为 true 时追加开/关 Issue 两条曲线,否则回落到总数曲线。列表中每个 name 都对应 collector.go 中的描述符(Organizations、Teams、Users、Repositories、Milestones、Stars、Releases、IssuesOpen、IssuesClosed、Issues)。如果你的 Gitea 版本不导出某个指标,把对应项从列表删掉即可,这正是 README 所说"Edit config.libsonnet if required"的含义。
issueLabels 默认提供 6 个常用标签的配色(bug、duplicate、invalid、enhancement、help wanted、question)。这些颜色在仪表盘里不是简单图例,而是通过 overview.libsonnet 顶部的 addIssueLabelsOverrides 函数,为每个标签生成一条 byRegexp matcher 的 field override,把对应序列固定为该颜色——因此你只需在 issueLabels 里增删 {label, color} 条目,图上分标签曲线就会自动换色。
六、生成的仪表盘长什么样:Gitea Overview 面板解析
overview.libsonnet 用 Grafonnet 的 grafana.dashboard.new(...) 构建 uid 为 gitea-overview 的仪表盘,全部查询统一带 job=~"$job", instance=~"$instance" 两个模板变量选择器,数据源也统一走 $datasource。
模板变量(4 个):
datasource:类型datasource、查询prometheus,默认文本 "Prometheus"——让导入后的仪表盘自动匹配任意 Prometheus 数据源;job:label_values(gitea_organizations, job),多选,allValue为.+——job 下拉框直接枚举抓到了哪些 Gitea 实例;instance:label_values(gitea_organizations{job="$job"}, instance),随 job 联动过滤;agg_interval:interval 型变量,query: '1m,10m,1h,1d,7d'、auto_min: '1m',供变化类面板做聚合区间。
面板与对应 PromQL(均带 {job=~"$job", instance=~"$instance"} 选择器):
| 面板 | 类型 | 查询 |
|---|---|---|
| Gitea stats | stat(lastNotNull,蓝色数值模式) |
giteaStatMetrics 列表中的每个指标名,图例取 description |
| Uptime | stat(area 图,单位秒) | time() - process_start_time_seconds{...} |
| Memory usage | timeseries(字节,绿色平滑) | process_resident_memory_bytes{...} |
| CPU usage | timeseries(百分比,绿→红渐变) | rate(process_cpu_seconds_total{...}[$__rate_interval]) * 100 |
| File descriptors usage | timeseries(双序列) | process_open_fds{...} 与 process_max_fds{...},上限序列被 override 成红色虚线 |
| Changes | stat(-- Dashboard -- 数据源,sum 聚合) |
引用下方"全量变化"面板的 refId A 求和 |
| Changes(图) | 堆叠柱状图(drawStyle: 'bars') |
changes(process_start_time_seconds{...}[$__interval]) > 0(重启计数,图例 "Restarts")+ 各 stat 指标 floor(delta(m{...}[$__interval])) > 0 |
| Issues by repository | 柱状图 + 汇总 stat | floor(increase(gitea_issues_by_repository{...}[$__interval])) > 0,图例 {{ repository }} |
| Issues by labels | 柱状图 + 汇总 stat,按 issueLabels 着色 |
floor(increase(gitea_issues_by_label{...}[$__interval])) > 0,图例 {{ label }} |
两个值得注意的实现细节:
- "Changes" 汇总面板用 Grafana 的
-- Dashboard --数据源引用兄弟面板(panelId指向变化图面板的静态 id200,refId: 'A'),把图里所有序列按sum汇成一个大数字,实现"本期共多少变化"的总览。 - 面板静态 id 刻意保留:变化图面板、分仓图(id
210)、分标签图(id220)及其汇总面板(211、221)是通过panels+:补丁方式而非.addPanel()写入的(源码注释写明 "use patching instead of .addPanel() to keep static ids"),因为-- Dashboard --引用依赖固定 id;而分仓/分标签两块又受showIssuesByRepository/showIssuesByLabel开关控制,用if ... else []条件拼接进面板数组。
进程级指标(process_*、time())来自 Prometheus 默认对 Go 应用采集的 standard library 指标,仓库级指标则全部落在 gitea_ 命名空间,与 collector.go 一一对应。
七、导入 Grafana,以及 alerts / rules 脚手架
构建完成后,把 dashboards_out/ 下的 JSON 文件导入你的 Grafana 服务器即可。README 强调导入方式与环境相关(UI 导入、provisioning、API 皆可)。由于仪表盘声明了 datasource 模板变量且默认查询 prometheus,导入后只需确认有一个可用的 Prometheus 数据源,且该数据源已配置抓取 Gitea 的 /metrics 端点(建议保留 job 标签以便多实例区分)。
此外,lib/ 目录下还有 alerts.jsonnet 与 rules.jsonnet 两个脚手架文件,分别通过 std.manifestYamlDoc 把 mixin 的 prometheusAlerts / prometheusRules 字段输出为 Prometheus 告警与规则 YAML。但就当前仓库代码结构看,mixin.libsonnet 只合并了 grafanaDashboards(仪表盘)与 _config(配置)两块,并未导出 prometheusAlerts/prometheusRules 字段,因此这两个入口目前属于为将来定义告警预留的骨架,Makefile 的默认构建也不会执行它们;如果你要落地告警,需要先在 mixin 侧补齐对应字段。
更高级的 mixin 用法(告警规则写法、与其他 mixin 组合等)可参考 monitoring-mixins 项目的官方文档(README 末尾给出的指引,此处不附外链)。
八、小结:一条命令的完整链路
把 README 的极简流程与源码对应起来,整条链路是:
[metrics] 配置开启 /metrics 端点(modules/setting/metrics.go)
→ Prometheus 抓取 gitea_* 指标(modules/metrics/collector.go)
→ jb install 拉取 grafonnet-lib(jsonnetfile.json)
→ jsonnet 求值 mixin.libsonnet(dashboards + config.libsonnet)
→ 输出 dashboards_out/gitea-overview.json(Makefile: dashboards_out)
→ 导入 Grafana,job/instance 变量自动枚举实例(overview.libsonnet)
关键文件速查:构建入口 Makefile 与 lib/dashboards.jsonnet、用户配置 config.libsonnet、面板实现 dashboards/overview.libsonnet、服务端指标开关 custom/conf/app.example.ini([metrics] 段)与 modules/setting/metrics.go、指标定义 modules/metrics/collector.go。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00