mcpField
P
promql-validator

promql-validator

github.com/akin-ozer云与 DevOps329612 次安装16 周前更新
代码仓库

关于 promql-validator

promql-validator 是用于检查和解释 PromQL 查询的技能,涵盖语法与语义检查、反模式检测及优化建议。它还通过交互式流程,将查询实际行为与用户意图进行比较。

主要功能

  1. 01检查 PromQL 语法
  2. 02评估指标类型用法与查询语义
  3. 03检测反模式和性能问题
  4. 04解释查询及其输出标签
  5. 05通过交互式规划优化查询

适用场景

  1. 01将查询加入仪表板前进行检查
  2. 02查找低效的过滤条件或聚合方式
  3. 03对照监控目标检查查询行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/akin-ozer/cc-devops-skills --skill promql-validator

安装后在 Claude Code 中输入/promql-validator确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

docs/
anti_patterns.md
best_practices.md
examples/
bad_queries.promql
good_queries.promql
optimization_examples.promql
scripts/
check_best_practices.py
test_validators.py
validate_syntax.py

详细介绍

此技能的工作方式

此技能会执行多级验证,并提供交互式查询规划:

  1. 语法验证:检查 PromQL 表达式的语法是否正确
  2. 语义验证:确保查询在逻辑上合理(例如,对计数器使用 rate(),而非对仪表盘使用)
  3. 反模式检测:识别常见错误和低效模式
  4. 优化建议:建议性能改进方案
  5. 查询说明:将 PromQL 转换为通俗易懂的英语
  6. 交互式规划:帮助用户明确意图并完善查询

工作流

用户提供 PromQL 查询时,请遵循以下工作流:

工作目录要求

请从仓库根目录运行验证命令,以确保相对路径正确解析:

cd "$(git rev-parse --show-toplevel)"

如果从其他位置运行,请使用 scripts/ 文件的绝对路径。

第 1 步:验证语法

运行语法验证脚本,检查基本正确性:

python3 devops-skills-plugin/skills/promql-validator/scripts/validate_syntax.py "<query>"

输出解析说明:

  • 退出码为 0:语法有效
  • 退出码非零:语法错误;包含 stderr 并指出具体词元/位置
  • 优先引用最小的错误片段,然后提供修正后的查询

脚本将检查:

  • 指标名称和标签匹配器是否有效
  • 运算符使用是否正确
  • 函数语法是否正确
  • 时间长度和范围是否有效
  • 括号和引号是否匹配
  • 修饰符(offset、@)使用是否正确
第 2 步:检查最佳实践

运行最佳实践检查器,以检测反模式和优化机会:

python3 devops-skills-plugin/skills/promql-validator/scripts/check_best_practices.py "<query>"

输出解析说明:

  • 将脚本各部分视为独立发现项(基数、指标类型误用、正则表达式误用等)
  • 如果脚本输出为空,但查询较复杂,请额外进行人工检查,并将其标记为 manual-review
  • 保留脚本对发现项的原有措辞,然后用通俗英语补充改进建议

脚本将识别:

  • 未使用标签过滤器的高基数查询
  • 本可使用精确匹配却使用了低效正则表达式匹配器的情况
  • 计数器指标缺少 rate()/increase() 的情况
  • 在仪表盘指标上使用 rate() 的情况
  • 对预先计算的分位数求平均值的情况
  • 时间范围过大的子查询
  • 在较长时间范围内使用 irate() 的情况
  • 添加更具体标签过滤器的机会
  • 应使用记录规则的复杂查询
第 3 步:说明查询

解析查询,并用通俗易懂的英语说明其作用:

  • 查询了哪些指标
  • 这些指标的类型(计数器、仪表盘、直方图、摘要)
  • 使用了哪些函数,以及使用原因
  • 查询计算的内容
  • 输出中会包含哪些标签
  • 预期结果的结构

必需的输出详情(始终明确包含以下内容):

**Output Labels**: [list labels that will be in the result, or "None (fully aggregated to scalar)"]
**Expected Result Structure**: [instant vector / range vector / scalar] with [N series / single value]

示例:

**Output Labels**: job, instance
**Expected Result Structure**: Instant vector with one series per job/instance combination
行号引用方法(必需)

在建议中引用示例/文档时,请包含文件路径和从 1 开始计数的行号:

examples/good_queries.promql:42
docs/best_practices.md:88

规则:

  • 引用最相关的单行(多行代码片段则引用起始行)
  • 引用范围要精确;不要引用整个文件
  • 如果无法获取行号,请说明 line number unavailable,并提供文件路径
步骤 4:交互式查询规划(阶段 1 - 停止并等待)

向用户提问以澄清问题,确认查询符合其意图:

  1. 了解目标:“你想监控或衡量什么?”

    • 请求率、错误率、延迟、资源使用情况等
  2. 确认指标类型:“这是计数器(始终递增)、仪表(可升可降)、直方图还是摘要?”

    • 这会影响要使用的函数
  3. 明确时间范围:“你需要哪个时间窗口?”

    • 即时值、随时间变化的速率、历史分析
  4. 确认聚合方式:“你需要跨标签聚合数据吗?如果需要,要按哪些标签聚合?”

    • by (job)、by (instance)、without (pod) 等
  5. 确认输出用途:“你是要将其用于告警、仪表板还是临时分析?”

    • 这会影响优化优先级

重要:两阶段对话

呈现步骤 1-4 的结果(语法、最佳实践、查询说明和意图问题)后:

⏸️ 在此处停止并等待用户回复

在用户回答澄清问题之前,不要继续执行步骤 5-7。 这样可以确保后续建议符合用户的实际意图。

步骤 5:比较意图与实现(阶段 2 - 用户回复后)

只有在用户回答了步骤 4 中的澄清问题后,才能继续执行此步骤。

了解用户的意图后:

  • 说明当前查询实际执行的操作
  • 指出意图与实现之间的任何不匹配之处
  • 如果查询不符合目标,建议进行修正
  • 如适用,提供替代方案

相关时,请说明已知限制:

  • 指出指标类型检测是基于启发式的(例如:“脚本根据 _bytes 后缀推断这是一个仪表。请确认是否正确。”)
  • 说明高基数警告可能是误报(例如:“如果你使用的是记录规则,或者确认基数较低,则此警告可能不适用。”)
步骤 6:提供优化建议

根据验证结果:

  • 建议更高效的查询模式
  • 对复杂或重复的查询,建议使用记录规则
  • 建议使用更合适的标签匹配器来降低基数
  • 建议采用适当的时间范围

参考示例:建议修正时,按以下格式引用相关示例:

As shown in `examples/bad_queries.promql` (lines 91-97):
❌ BAD: `avg(http_request_duration_seconds{quantile="0.95"})`
✅ GOOD: Use histogram_quantile() with histogram buckets

引用来源:

  • examples/good_queries.promql - 规范模式
  • examples/optimization_examples.promql - 优化前后对比
  • examples/bad_queries.promql - 展示应避免的写法
  • docs/best_practices.md - 详细说明
  • docs/anti_patterns.md - 反模式深入解析

引用格式:file_path (lines X-Y),并引用相关代码片段

步骤 7:让用户规划和改进

让用户掌握主动权:

  • 询问他们是否想修改查询
  • 提供帮助,重写查询以提升性能
  • 如适用,提供多个替代方案
  • 说明不同方法之间的权衡

关键验证规则

语法规则
  1. 指标名称:必须匹配 [a-zA-Z_:][a-zA-Z0-9_:]*,或使用 UTF-8 引号语法(Prometheus 3.0+):
    • 引号形式:{"my.metric.with.dots"}
    • 使用 name 标签:{__name__="my.metric.with.dots"}
  2. 标签匹配器:=(等于)、!=(不等于)、=~(正则匹配)、!~(正则不匹配)
  3. 时间长度:[0-9]+(ms|s|m|h|d|w|y) - 例如,5m、1h、7d
  4. 范围向量:metric_name[duration] - 例如,http_requests_total[5m]
  5. 偏移修饰符:offset <duration> - 例如,metric_name offset 5m
  6. @ 修饰符:@ <timestamp> 或 @ start() / @ end()
语义规则
  1. rate() 和 irate():仅应与计数器指标(以 _total、_count、_sum 或 _bucket 结尾的指标)搭配使用
  2. 计数器:通常应使用 rate() 或 increase(),而不是原始值
  3. 仪表盘:不应使用 rate() 或 increase()
  4. 直方图:应使用带有 le 标签的 histogram_quantile(),并对 _bucket 指标使用 rate()
  5. 摘要:不要对分位数求平均;应根据 _sum 和 _count 计算
  6. 聚合:使用 by() 或 without() 控制输出标签
性能规则
  1. 基数:始终使用具体的标签匹配器来减少时间序列数量
  2. 正则表达式:如果可能,应使用 = 而不是 =~ 进行精确匹配
  3. 速率范围:应至少为抓取间隔的 4 倍(通常最小为 [2m])
  4. irate():最适用于较短范围(<5m);较长时间段应使用 rate()
  5. 子查询:避免使用过长的时间范围,以免处理数百万个样本
  6. 记录规则:对于频繁访问的复杂查询,应使用记录规则

需要检测的反模式

高基数问题

❌ 错误:http_requests_total{}

  • 未经过滤便匹配所有时间序列

✅ 正确:http_requests_total{job="api", instance="prod-1"}

  • 具体的标签筛选条件可降低基数
过度使用正则表达式

❌ 错误:http_requests_total{status=~"2.."}

  • 正则表达式速度较慢,且不够精确

✅ 正确:http_requests_total{status="200"}

  • 精确匹配速度更快
计数器缺少 rate()

❌ 错误:http_requests_total

  • 计数器原始值没有实用价值(始终递增)

✅ 正确:rate(http_requests_total[5m])

  • 速率表示每秒请求数
对仪表盘使用 rate()

❌ 错误:rate(memory_usage_bytes[5m])

  • 仪表盘衡量当前状态,而非累积值

✅ 正确:memory_usage_bytes

  • 直接使用仪表盘值,或搭配 avg_over_time()
对分位数求平均

❌ 错误:avg(http_request_duration_seconds{quantile="0.95"})

  • 对预先计算的分位数求平均在数学上无效

✅ 正确:histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

  • 根据直方图桶计算分位数
子查询范围过长

❌ 错误:rate(metric[5m])[90d:1m]

  • 会处理数百万个样本,速度非常慢

✅ 正确:使用记录规则,或将范围限制在所需时长内

在较长范围内使用 irate()

❌ 错误:irate(metric[1h])

  • irate() 只查看最后两个样本,范围设置毫无意义

✅ 正确:rate(metric[1h]) 或 irate(metric[5m])

  • 较长范围应使用 rate(),或缩短 irate() 的范围
混用指标类型

❌ 错误:avg(http_request_duration_seconds{quantile="0.95"}) / rate(node_memory_usage_bytes[1h]) + sum(http_requests_total)

  • 将摘要分位数、仪表盘指标和计数器用于算术运算
  • 会产生毫无意义的结果

✅ 正确:将每种指标类型分别放在用途明确的查询中:

  • 延迟:histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
  • 内存:node_memory_usage_bytes{instance="prod-1"}
  • 请求速率:rate(http_requests_total{job="api"}[5m])

输出格式

请按以下结构提供验证结果:

## PromQL Validation Results

### Syntax Check
- Status: ✅ VALID / ⚠️ WARNING / ❌ ERROR
- Issues: [list any syntax errors with line/position]

### Semantic Check
- Status: ✅ VALID / ⚠️ WARNING / ❌ ERROR
- Issues: [list any logical problems]

### Performance Analysis
- Status: ✅ OPTIMIZED / ⚠️ CAN BE IMPROVED / ❌ INEFFICIENT
- Issues: [list optimization opportunities]
- Suggestions: [specific improvements]

### Query Explanation
Your query: `<query>`

This query does:
- [Plain English explanation]
- Metrics: [list metrics and their types]
- Functions: [explain each function]
- Output: [describe result structure]

### Intent Verification
Let me verify this matches your needs:

1. What are you trying to measure? [your goal here]
2. Is this a counter/gauge/histogram/summary? [metric type]
3. What time range interests you? [time window]
4. Do you need aggregation? If so, by which labels? [aggregation needs]
5. Is this for alerting, dashboarding, or analysis? [use case]

### Recommendations
[Based on the analysis, suggest improvements or alternatives]

交互式对话

验证后,继续对话:

Claude:“我已验证你的查询。语法正确,但我注意到它查询 http_requests_total 时没有任何标签筛选条件。这可能匹配数千条时间序列。你想监控哪个具体服务或端点?”

User:[提供意图]

Claude:“很好!根据你的需求,下面是优化后的版本:rate(http_requests_total{job="api-service", path="/users"}[5m])。这会计算过去 5 分钟内发往 /users 端点的每秒速率。这样符合你的需求吗?”

User:[确认或要求修改]

Claude:[提供优化后的查询或替代方案]

示例

请参阅 examples/ 目录:

  • good_queries.promql:遵循最佳实践的优质查询
  • bad_queries.promql:常见错误和反模式(附修正方法)
  • optimization_examples.promql:优化前后的示例

文档

请参阅 docs/ 目录:

  • best_practices.md:全面的 PromQL 最佳实践指南
  • anti_patterns.md:详细的反模式参考及说明

重要说明

  1. 积极互动:始终提出澄清问题,了解用户意图
  2. 注重讲解:说明问题出在哪里以及原因,而不只是指出有问题
  3. 提供帮助:主动提出重写查询,而不只是批评
  4. 结合上下文:考虑用户的使用场景(告警还是仪表盘)
  5. 全面检查:检查所有四个层面(语法、语义、性能、意图)
  6. 注重实用:建议切实可行的优化,而非理论上的完美方案

集成

此技能可用于:

  • 独立进行查询审查
  • 设置监控时验证告警规则
  • 排查缓慢的 Prometheus 查询
  • 作为代码审查的一部分检查记录规则
  • 向团队成员讲解 PromQL

验证工具

此技能使用两个主要的 Python 脚本:

  1. validate_syntax.py:使用正则表达式进行纯语法检查
  2. check_best_practices.py:进行语义和性能分析

两个脚本都会输出 JSON,以便程序化解析;也会输出便于阅读的消息供人查看。

成功标准

一次成功的验证应当:

  1. 找出所有语法错误
  2. 检测语义问题
  3. 至少提出一项优化建议(如适用)
  4. 清楚说明查询的作用
  5. 确认查询符合用户意图
  6. 提供可执行的后续步骤

已知限制

验证脚本存在一些需要注意的限制:

指标类型检测
  • 基于启发式规则:根据命名约定(例如 _total、_bytes)推断指标类型(counter、gauge、histogram、summary)
  • 自定义指标:名称不符合标准的指标可能无法正确分类
  • 建议:如果脚本无法确定指标类型,请向用户确认
高基数检测
  • 保守做法:脚本会标记未指定标签选择器的指标,但某些使用场景确实需要查询所有时间序列
  • 记录规则:使用记录规则指标(例如 job:http_requests:rate5m)的查询无需标签过滤器也有效
  • 建议:根据实际情况判断——如果用户确定其基数可控,可以放心忽略警告
语义验证
  • 没有运行时上下文:脚本无法验证指标是否实际存在,也无法确认标签值是否有效
  • 不依赖特定架构:不了解特定 Prometheus 部署或指标架构
  • 建议:进行生产环境验证时,请在实际的 Prometheus 实例上测试查询
脚本检测覆盖范围

脚本可以检测常见反模式,但无法发现:

  • 业务逻辑错误(例如,计算了错误的 KPI)
  • 特定上下文的优化(取决于抓取间隔、保留期等)
  • 扩展提供的自定义函数行为

请记住

目标不仅是验证查询,更是帮助用户编写更好的 PromQL,并理解其监控数据。始终注重讲解、积极互动并提供帮助!

评论

支持 Markdown