在 Prometheus 的 `label_values()` 函数使用中,一个常见问题是:**如何仅获取包含特定字符串(如 `"prod"` 或 `"api_"`)的 label 值?**
`label_values()` 本身不支持正则匹配或子串过滤,它仅返回某 metric 下指定 label 的所有原始取值(如 `label_values(http_requests_total, job)` 返回所有 `job` 值)。若想筛选含特定字段的值(例如只取 `job` 中以 `"api-"` 开头的实例),直接调用 `label_values()` 无法实现。用户常误以为可结合 Rego、PromQL 过滤或外部工具(如 Grafana 变量查询)一并完成,结果导致变量为空或漏配。正确解法需分层处理:先通过 `count by (label_name)` + `regex` 匹配的 PromQL 查询预筛数据(如 `count by (job) (http_requests_total{job=~"api-.*"})`),再配合 Grafana 的「Custom」或「Query」类型变量 + API 代理/Recording Rule 预计算,或借助 Prometheus API + 外部脚本做后处理。忽略该限制易引发监控面板下拉选项缺失、告警配置失效等生产问题。
1条回答 默认 最新
Airbnb爱彼迎 2026-04-04 06:05关注```html一、现象层:为什么
label_values()无法直接做子串过滤?在 Grafana 变量配置中,
label_values(http_requests_total, job)会返回所有joblabel 的原始值(如"api-auth","prod-db","ci-runner"),但它不接受任何 PromQL 过滤器或正则表达式参数。其底层调用的是 Prometheus 的/api/v1/labels和/api/v1/label/<name>/values端点,仅提供“全量枚举”,无服务端计算能力。这是设计使然——Prometheus 标签值索引是倒排的,但不支持模糊匹配查询。二、机理层:Prometheus 标签系统的存储与查询边界
- 标签值存储:基于 LSM-Tree 的 chunk 存储 + 内存中的 label index,仅支持精确匹配(
=)、前缀匹配(=~ "prefix.*")和集合匹配(=~ "a|b|c") - API 层限制:
/api/v1/label/<name>/values不支持match[]参数,而/api/v1/series虽支持match[],但返回的是时间序列元数据(含完整 label set),需客户端解析 - PromQL 表达式语义:
count by (job)是聚合操作,可结合{job=~"api_.*"}实现逻辑筛选,但该结果仍是指标向量,非纯字符串列表
三、实践层:四种生产级可行方案对比
方案 适用场景 延迟/维护成本 Grafana 变量类型 是否需额外组件 ✅ Recording Rule + label_values()高频访问、稳定 label 模式(如 job=~"prod.*")低(每 scrape interval 计算一次) Query 否 ✅ Prometheus API + Grafana Query 变量 动态性强、需实时响应(如按命名空间筛选 pod) 中(每次变量刷新触发 HTTP 请求) Query 否(仅需 Grafana 7.2+) ⚠️ 外部脚本代理(如 Python FastAPI) 复杂逻辑(多 label 关联、白名单校验、缓存策略) 高(需部署、监控、TLS 配置) Custom / API 是 四、架构层:推荐的分层处理流程图
flowchart LR A[用户在 Grafana 选择变量] --> B{Grafana 变量类型} B -->|Query 类型| C[向 Prometheus /api/v1/series 发起 match[] 查询] B -->|Custom 类型| D[调用预置静态列表或外部 API] C --> E[解析响应中的 target label 值] E --> F[去重 & 排序] F --> G[渲染下拉菜单] D --> G C -.-> H[建议添加 caching: 30s] E -.-> I[避免返回 >500 条导致 UI 卡顿]五、代码层:可即用的 PromQL + Grafana 配置示例
Recording Rule(写入 prometheus.yml):
groups: - name: filtered_job_labels rules: - record: job:filtered_api_prod expr: count by (job) (http_requests_total{job=~"api_.*|prod.*"})Grafana Query 变量(Type=Query):
label_values(job:filtered_api_prod, job)或直连 API(Grafana 9+ 支持):
https://prometheus.example.com/api/v1/series?match[]={job=~"api_.*|prod.*"}&start=now-1h(注意:需在 Grafana 数据源中启用 “Direct” 访问模式,并配置 CORS)
六、陷阱层:五个高频误用及后果
- 在
label_values()中错误拼接 PromQL:label_values(count by (job)(...), job)→ 语法错误,Grafana 报invalid parameter "query" - 使用
regex函数于 PromQL 表达式中再套label_values()→regex是客户端函数,Prometheus 不识别 - 忽略 label cardinality:当
job=~"prod.*"匹配到 2000+ 值时,Grafana 渲染卡顿甚至 OOM - 未设置变量 refresh on time range change → 时间范围切换后仍显示旧 label,造成误判
- 将
label_values(up{job=~"api.*"}, instance)用于告警规则模板 → 告警引擎不支持动态 label 查询,导致template execution error
七、演进层:未来可观测性栈的替代路径
随着 OpenTelemetry Collector 和 Cortex/Mimir 的普及,更健壮的方案正在浮现:
- OTel Attribute Filtering:在采集侧通过
attributes_processor提前注入env_type="prod"等语义化 label,降低查询复杂度 - Mimir Label Indexing Extensions:Mimir v1.12+ 支持
/api/v1/label_values?match[]=...,已突破原生 Prometheus 限制 - Grafana 10+ 的 Unified Alerting + Labels API:允许在 alert rule 中引用
labels_from_query,实现告警维度与面板变量同源
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- 标签值存储:基于 LSM-Tree 的 chunk 存储 + 内存中的 label index,仅支持精确匹配(